blob: 2386625811f8bf2a104e088007fd15e80ed0f5d3 [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
Jeff Johnson295189b2012-06-20 16:38:30 -0700118
119 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700120 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
121 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700122 )
123 {
124 tANI_U8 sessionId = pAdapter->sessionId;
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800125 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
126 {
127 sme_DeregisterMgmtFrame(
128 hHal, sessionId,
129 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
130 NULL, 0 );
131 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700132 }
133 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
134 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
135 )
136 {
137 WLANSAP_DeRegisterMgmtFrame(
138 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
139 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
140 NULL, 0 );
141 }
142
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800143 vos_mem_free( pRemainChanCtx );
Jeff Johnson295189b2012-06-20 16:38:30 -0700144 complete(&pAdapter->cancel_rem_on_chan_var);
145 return eHAL_STATUS_SUCCESS;
146}
147
Jeff Johnson32d95a32012-09-10 13:15:23 -0700148static void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700149{
Jeff Johnson295189b2012-06-20 16:38:30 -0700150 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
151 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700152
Jeff Johnson32d95a32012-09-10 13:15:23 -0700153 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700154 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700155 hddLog( LOG1, "Cancel Existing Remain on Channel");
156
157 /* Wait till remain on channel ready indication before issuing cancel
158 * remain on channel request, otherwise if remain on channel not
159 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700160 * will be in unknown state.
161 */
162 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
163 msecs_to_jiffies(WAIT_REM_CHAN_READY));
164 if (!status)
165 {
166 hddLog( LOGE,
167 "%s: timeout waiting for remain on channel ready indication",
168 __func__);
169 }
170
171 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700172
Jeff Johnson295189b2012-06-20 16:38:30 -0700173 /* Issue abort remain on chan request to sme.
174 * The remain on channel callback will make sure the remain_on_chan
175 * expired event is sent.
176 */
177 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700178 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
179 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700180 )
181 {
182 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
183 pAdapter->sessionId );
184 }
185 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
186 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
187 )
188 {
189 WLANSAP_CancelRemainOnChannel(
190 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
191 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700192
Jeff Johnson32d95a32012-09-10 13:15:23 -0700193 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700194 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700195
196 if (!status)
197 {
198 hddLog( LOGE,
199 "%s: timeout waiting for cancel remain on channel ready indication",
200 __func__);
201 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700202 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700203}
204
205int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
206{
207 int status = 0;
208 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
209
210 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
211 {
212 //Cancel Existing Remain On Channel
213 //If no action frame is pending
214 if( cfgState->remain_on_chan_ctx != NULL)
215 {
216 //Check whether Action Frame is pending or not
217 if( cfgState->buf == NULL)
218 {
219 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
220 }
221 else
222 {
223 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
224 status = -EBUSY;
225 }
226 }
227 }
228 return status;
229}
230
231static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
232 struct net_device *dev,
233 struct ieee80211_channel *chan,
234 enum nl80211_channel_type channel_type,
235 unsigned int duration, u64 *cookie,
236 rem_on_channel_request_type_t request_type )
237{
238 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
239 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
240 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
241 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
242 __func__,pAdapter->device_mode);
243
244 hddLog( LOG1,
245 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
246 chan->hw_value, chan->center_freq, channel_type, duration );
247
248 //Cancel existing remain On Channel if any
249 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700250
Jeff Johnsone7245742012-09-05 17:12:55 -0700251 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700252 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700253 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700254 * channel requets when Load/Unload is in progress*/
255 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
256 {
257 hddLog( LOGE,
258 "%s: Wlan Load/Unload is in progress", __func__);
259 return -EBUSY;
260 }
261
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700262 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
263 {
264 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
265 "%s:LOGP in Progress. Ignore!!!", __func__);
266 return -EAGAIN;
267 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700268 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
269 if( NULL == pRemainChanCtx )
270 {
271 hddLog(VOS_TRACE_LEVEL_FATAL,
272 "%s: Not able to allocate memory for Channel context",
273 __func__);
274 return -ENOMEM;
275 }
276
277 vos_mem_copy( &pRemainChanCtx->chan, chan,
278 sizeof(struct ieee80211_channel) );
279
280 pRemainChanCtx->chan_type = channel_type;
281 pRemainChanCtx->duration = duration;
282 pRemainChanCtx->dev = dev;
283 *cookie = (tANI_U32) pRemainChanCtx;
284 pRemainChanCtx->cookie = *cookie;
285 pRemainChanCtx->rem_on_chan_request = request_type;
286 cfgState->remain_on_chan_ctx = pRemainChanCtx;
287 cfgState->current_freq = chan->center_freq;
288
289 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
290
291 //call sme API to start remain on channel.
292 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700293 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
294 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700295 )
296 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700297 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700298 //call sme API to start remain on channel.
299 sme_RemainOnChannel(
300 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
301 chan->hw_value, duration,
302 wlan_hdd_remain_on_channel_callback, pAdapter );
303
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800304 if( REMAIN_ON_CHANNEL_REQUEST == request_type)
305 {
306 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
307 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
308 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
309 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700310
311 }
312 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
313 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
314 )
315 {
316 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700317 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700318 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
319 chan->hw_value, duration,
320 wlan_hdd_remain_on_channel_callback, pAdapter ))
321
322 {
323 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
324 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
325 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700326 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700327 return -EINVAL;
328 }
329
330
Jeff Johnson43971f52012-07-17 12:26:56 -0700331 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700332 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
333 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
334 NULL, 0 ))
335 {
336 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
337 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
338 WLANSAP_CancelRemainOnChannel(
339 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
340 return -EINVAL;
341 }
342
343 }
344 return 0;
345
346}
347
348int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
349 struct net_device *dev,
350 struct ieee80211_channel *chan,
351 enum nl80211_channel_type channel_type,
352 unsigned int duration, u64 *cookie )
353{
354 return wlan_hdd_request_remain_on_channel(wiphy, dev,
355 chan, channel_type, duration, cookie,
356 REMAIN_ON_CHANNEL_REQUEST);
357}
358
359void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
360{
361 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
362 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
363
364 hddLog( LOG1, "Ready on chan ind");
365
366 if( pRemainChanCtx != NULL )
367 {
368 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
369 {
370 cfg80211_ready_on_channel( pAdapter->dev, (tANI_U32)pRemainChanCtx,
371 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
372 pRemainChanCtx->duration, GFP_KERNEL );
373 }
374#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
375 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
376 {
377 complete(&pAdapter->offchannel_tx_event);
378 }
379#endif
380 complete(&pAdapter->rem_on_chan_ready_event);
381 }
382 else
383 {
384 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
385 }
386 return;
387}
388
389int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
390 struct net_device *dev, u64 cookie )
391{
392 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700393 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
394 int status = 0;
395
396 hddLog( LOG1, "Cancel remain on channel req");
397
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700398 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
399 {
400 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
401 "%s:LOGP in Progress. Ignore!!!", __func__);
402 return -EAGAIN;
403 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700404 /* FIXME cancel currently running remain on chan.
405 * Need to check cookie and cancel accordingly
406 */
407 if( (cfgState->remain_on_chan_ctx == NULL) ||
408 (cfgState->remain_on_chan_ctx->cookie != cookie) )
409 {
410 hddLog( LOGE,
411 "%s: No Remain on channel pending with specified cookie value",
412 __func__);
413 return -EINVAL;
414 }
415
416 /* wait until remain on channel ready event received
417 * for already issued remain on channel request */
418 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
419 msecs_to_jiffies(WAIT_REM_CHAN_READY));
420 if (!status)
421 {
422 hddLog( LOGE,
423 "%s: timeout waiting for remain on channel ready indication",
424 __func__);
425 }
426 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
427 /* Issue abort remain on chan request to sme.
428 * The remain on channel callback will make sure the remain_on_chan
429 * expired event is sent.
430 */
431 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700432 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
433 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700434 )
435 {
436 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700437 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
438 sessionId );
439 }
440 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
441 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
442 )
443 {
444 WLANSAP_CancelRemainOnChannel(
445 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
446 }
447 else
448 {
449 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
450 __func__, pAdapter->device_mode);
451 return -EIO;
452 }
453 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
454 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
455 return 0;
456}
457
458#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
459int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
460 struct ieee80211_channel *chan, bool offchan,
461 enum nl80211_channel_type channel_type,
462 bool channel_type_valid, unsigned int wait,
463 const u8 *buf, size_t len, bool no_cck,
464 bool dont_wait_for_ack, u64 *cookie )
465#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
466int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
467 struct ieee80211_channel *chan, bool offchan,
468 enum nl80211_channel_type channel_type,
469 bool channel_type_valid, unsigned int wait,
470 const u8 *buf, size_t len, u64 *cookie )
471#else
472int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
473 struct ieee80211_channel *chan,
474 enum nl80211_channel_type channel_type,
475 bool channel_type_valid,
476 const u8 *buf, size_t len, u64 *cookie )
477#endif //LINUX_VERSION_CODE
478{
479 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
480 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700481 tANI_U16 extendedWait = 0;
482 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
483 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
484 tActionFrmType actionFrmType;
485 bool noack = 0;
486
Jeff Johnson295189b2012-06-20 16:38:30 -0700487#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
488 hdd_adapter_t *goAdapter;
489#endif
490
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700491#ifdef WLAN_FEATURE_P2P_DEBUG
492 if ((type == SIR_MAC_MGMT_FRAME) &&
493 (subType == SIR_MAC_MGMT_ACTION) &&
494 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
495 {
496 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
497 if(actionFrmType > MAX_P2P_ACTION_FRAME_TYPE)
498 {
499 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA",
500 actionFrmType);
501 }
502 else
503 {
504 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA",
505 p2p_action_frame_type[actionFrmType]);
506 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
507 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
508 {
509 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
510 hddLog(LOGE,"[P2P State]Inactive state to "
511 "GO negotation progress state");
512 }
513 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
514 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
515 {
516 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
517 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
518 " completed state");
519 }
520 }
521 }
522#endif
523
Jeff Johnsone7245742012-09-05 17:12:55 -0700524#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
525 noack = dont_wait_for_ack;
526#endif
527
528 //If the wait is coming as 0 with off channel set
529 //then set the wait to 200 ms
530 if (offchan && !wait)
531 wait = ACTION_FRAME_DEFAULT_WAIT;
532
Jeff Johnson295189b2012-06-20 16:38:30 -0700533 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
534 __func__,pAdapter->device_mode);
535
536 //Call sme API to send out a action frame.
537 // OR can we send it directly through data path??
538 // After tx completion send tx status back.
539 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
540 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
541 )
542 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700543 if (type == SIR_MAC_MGMT_FRAME)
544 {
545 if (subType == SIR_MAC_MGMT_PROBE_RSP)
546 {
547 /* Drop Probe response recieved from supplicant, as for GO and
548 SAP PE itself sends probe response
549 */
550 goto err_rem_channel;
551 }
552 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
553 (subType == SIR_MAC_MGMT_DEAUTH))
554 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700555 /* During EAP failure or P2P Group Remove supplicant
556 * is sending del_station command to driver. From
557 * del_station function, Driver will send deauth frame to
558 * p2p client. No need to send disassoc frame from here.
559 * so Drop the frame here and send tx indication back to
560 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700561 */
562 tANI_U8 dstMac[ETH_ALEN] = {0};
563 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700564 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700565 "%s: Deauth/Disassoc received for STA:"
Jeff Johnsone7245742012-09-05 17:12:55 -0700566 "%02x:%02x:%02x:%02x:%02x:%02x",
567 __func__,
568 dstMac[0], dstMac[1], dstMac[2],
Jeff Johnson295189b2012-06-20 16:38:30 -0700569 dstMac[3], dstMac[4], dstMac[5]);
Jeff Johnson295189b2012-06-20 16:38:30 -0700570 goto err_rem_channel;
571 }
572 }
573 }
574
575 if( NULL != cfgState->buf )
576 return -EBUSY;
577
578 hddLog( LOG1, "Action frame tx request");
579
580#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
581 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
582
583 //If GO adapter exists and operating on same frequency
584 //then we will not request remain on channel
585 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
586 == goAdapter->sessionCtx.ap.operatingChannel ) )
587 {
588 goto send_frame;
589 }
590#endif
591
592#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
593 if( offchan && wait)
594 {
595 int status;
596
597 // In case of P2P Client mode if we are already
598 // on the same channel then send the frame directly
599
600 if((cfgState->remain_on_chan_ctx != NULL) &&
601 (cfgState->current_freq == chan->center_freq)
602 )
603 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700604 hddLog(LOG1,"action frame: extending the wait time\n");
605 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700606 goto send_frame;
607 }
608
609 INIT_COMPLETION(pAdapter->offchannel_tx_event);
610
611 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
612 chan, channel_type, wait, cookie,
613 OFF_CHANNEL_ACTION_TX);
614
615 if(0 != status)
616 {
617 if( (-EBUSY == status) &&
618 (cfgState->current_freq == chan->center_freq) )
619 {
620 goto send_frame;
621 }
622 goto err_rem_channel;
623 }
624
625 /* Wait for driver to be ready on the requested channel */
626 status = wait_for_completion_interruptible_timeout(
627 &pAdapter->offchannel_tx_event,
628 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
629 if(!status)
630 {
631 hddLog( LOGE, "Not able to complete remain on channel request"
632 " within timeout period");
633 goto err_rem_channel;
634 }
635 }
636 else if ( offchan )
637 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700638 /* Check before sending action frame
639 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700640 if(NULL == cfgState->remain_on_chan_ctx)
641 {
642 goto err_rem_channel;
643 }
644 }
645 send_frame:
646#endif
647
Jeff Johnsone7245742012-09-05 17:12:55 -0700648 if(!noack)
649 {
650 cfgState->buf = vos_mem_malloc( len ); //buf;
651 if( cfgState->buf == NULL )
652 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700653
Jeff Johnsone7245742012-09-05 17:12:55 -0700654 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700655
Jeff Johnsone7245742012-09-05 17:12:55 -0700656 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700657
658#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700659 if( cfgState->remain_on_chan_ctx )
660 {
661 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
662 *cookie = cfgState->action_cookie;
663 }
664 else
665 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700666#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700667 *cookie = (tANI_U32) cfgState->buf;
668 cfgState->action_cookie = *cookie;
Jeff Johnson295189b2012-06-20 16:38:30 -0700669#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700670 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700671#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700672 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700673
674 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700675 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
676 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700677 )
678 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700679 tANI_U8 sessionId = pAdapter->sessionId;
680 if ((type == SIR_MAC_MGMT_FRAME) &&
681 (subType == SIR_MAC_MGMT_ACTION) &&
682 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700683 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700684 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
685 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
686 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700687 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700688 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
689 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
690 }
691 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
692 {
693 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
694 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700695 }
696 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700697
Jeff Johnson295189b2012-06-20 16:38:30 -0700698 if (eHAL_STATUS_SUCCESS !=
699 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700700 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700701 {
702 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
703 "%s: sme_sendAction returned fail", __func__);
704 goto err;
705 }
706 }
707 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
708 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
709 )
710 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700711 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700712 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700713 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700714 {
715 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
716 "%s: WLANSAP_SendAction returned fail", __func__);
717 goto err;
718 }
719 }
720
721 return 0;
722err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700723 if(!noack)
724 {
725 hdd_sendActionCnf( pAdapter, FALSE );
726 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700727 return 0;
728err_rem_channel:
729 *cookie = (tANI_U32)cfgState;
730 cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL );
731 return 0;
732}
733
734#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
735int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
736 struct net_device *dev,
737 u64 cookie)
738{
739 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
740}
741#endif
742
743void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
744{
745 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
746
Jeff Johnsone7245742012-09-05 17:12:55 -0700747 cfgState->actionFrmState = HDD_IDLE;
748
Jeff Johnson295189b2012-06-20 16:38:30 -0700749 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
750 if( NULL == cfgState->buf )
751 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700752 return;
753 }
754
755 /* If skb is NULL it means this packet was received on CFG80211 interface
756 * else it was received on Monitor interface */
757 if( cfgState->skb == NULL )
758 {
759 /*
760 * buf is the same pointer it passed us to send. Since we are sending
761 * it through control path, we use different buffers.
762 * In case of mac80211, they just push it to the skb and pass the same
763 * data while sending tx ack status.
764 * */
765 cfg80211_mgmt_tx_status( pAdapter->dev, cfgState->action_cookie,
766 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
767 vos_mem_free( cfgState->buf );
768 cfgState->buf = NULL;
769 }
770 else
771 {
772 hdd_adapter_t* pMonAdapter =
773 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
774 if( pMonAdapter == NULL )
775 {
776 hddLog( LOGE, "Not able to get Monitor Adapter");
777 cfgState->skb = NULL;
778 vos_mem_free( cfgState->buf );
779 cfgState->buf = NULL;
780 complete(&pAdapter->tx_action_cnf_event);
781 return;
782 }
783 /* Send TX completion feedback over monitor interface. */
784 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
785 cfgState->skb = NULL;
786 vos_mem_free( cfgState->buf );
787 cfgState->buf = NULL;
788 /* Look for the next Mgmt packet to TX */
789 hdd_mon_tx_mgmt_pkt(pAdapter);
790 }
791 complete(&pAdapter->tx_action_cnf_event);
792}
793
794/**
795 * hdd_setP2pNoa
796 *
797 *FUNCTION:
798 * This function is called from hdd_hostapd_ioctl function when Driver
799 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
800 *
801 *LOGIC:
802 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
803 *
804 *ASSUMPTIONS:
805 *
806 *
807 *NOTE:
808 *
809 * @param dev Pointer to net device structure
810 * @param command Pointer to command
811 *
812 * @return Status
813 */
814
815int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
816{
817 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
818 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
819 VOS_STATUS status = VOS_STATUS_SUCCESS;
820 tP2pPsConfig NoA;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800821 int count, duration, start_time;
Jeff Johnson295189b2012-06-20 16:38:30 -0700822 char *param;
823
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800824 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700825 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800826 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700827 param++;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800828 sscanf(param, "%d %d %d", &count, &start_time, &duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700829 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
830 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800831 __func__, count, start_time, duration);
832 duration = MS_TO_MUS(duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700833 /* PS Selection
834 * Periodic NoA (2)
835 * Single NOA (4)
836 */
837 NoA.opp_ps = 0;
838 NoA.ctWindow = 0;
839 if (count == 1)
840 {
841 NoA.duration = 0;
842 NoA.single_noa_duration = duration;
843 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
844 }
845 else
846 {
847 NoA.duration = duration;
848 NoA.single_noa_duration = 0;
849 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
850 }
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800851 NoA.interval = MS_TO_MUS(100);
Jeff Johnson295189b2012-06-20 16:38:30 -0700852 NoA.count = count;
853 NoA.sessionid = pAdapter->sessionId;
854
855 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
856 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
857 "interval %d count %d single noa duration %d "
858 "PsSelection %x \n", __func__, NoA.opp_ps,
859 NoA.ctWindow, NoA.duration, NoA.interval,
860 NoA.count, NoA.single_noa_duration,
861 NoA.psSelection);
862
863 sme_p2pSetPs(hHal, &NoA);
864 return status;
865}
866
867/**
868 * hdd_setP2pOpps
869 *
870 *FUNCTION:
871 * This function is called from hdd_hostapd_ioctl function when Driver
872 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
873 *
874 *LOGIC:
875 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
876 *
877 *ASSUMPTIONS:
878 *
879 *
880 *NOTE:
881 *
882 * @param dev Pointer to net device structure
883 * @param command Pointer to command
884 *
885 * @return Status
886 */
887
888int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
889{
890 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
891 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
892 VOS_STATUS status = VOS_STATUS_SUCCESS;
893 tP2pPsConfig NoA;
894 char *param;
895 int legacy_ps, opp_ps, ctwindow;
896
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800897 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700898 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800899 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700900 param++;
901 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
902 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
903 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
904 __func__, legacy_ps, opp_ps, ctwindow);
905
906 /* PS Selection
907 * Opportunistic Power Save (1)
908 */
909
910 /* From wpa_cli user need to use separate command to set ctWindow and Opps
911 * When user want to set ctWindow during that time other parameters
912 * values are coming from wpa_supplicant as -1.
913 * Example : User want to set ctWindow with 30 then wpa_cli command :
914 * P2P_SET ctwindow 30
915 * Command Received at hdd_hostapd_ioctl is as below:
916 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
917 */
918 if (ctwindow != -1)
919 {
920
921 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
922 "Opportunistic Power Save is %s \n",
923 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
924
925 if (ctwindow != pAdapter->ctw)
926 {
927 pAdapter->ctw = ctwindow;
928
929 if(pAdapter->ops)
930 {
931 NoA.opp_ps = pAdapter->ops;
932 NoA.ctWindow = pAdapter->ctw;
933 NoA.duration = 0;
934 NoA.single_noa_duration = 0;
935 NoA.interval = 0;
936 NoA.count = 0;
937 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
938 NoA.sessionid = pAdapter->sessionId;
939
940 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
941 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
942 "interval %d count %d single noa duration %d "
943 "PsSelection %x \n", __func__, NoA.opp_ps,
944 NoA.ctWindow, NoA.duration, NoA.interval,
945 NoA.count, NoA.single_noa_duration,
946 NoA.psSelection);
947
948 sme_p2pSetPs(hHal, &NoA);
949 }
950 return 0;
951 }
952 }
953
954 if (opp_ps != -1)
955 {
956 pAdapter->ops = opp_ps;
957
958 if ((opp_ps != -1) && (pAdapter->ctw))
959 {
960 NoA.opp_ps = opp_ps;
961 NoA.ctWindow = pAdapter->ctw;
962 NoA.duration = 0;
963 NoA.single_noa_duration = 0;
964 NoA.interval = 0;
965 NoA.count = 0;
966 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
967 NoA.sessionid = pAdapter->sessionId;
968
969 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
970 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
971 "interval %d count %d single noa duration %d "
972 "PsSelection %x \n", __func__, NoA.opp_ps,
973 NoA.ctWindow, NoA.duration, NoA.interval,
974 NoA.count, NoA.single_noa_duration,
975 NoA.psSelection);
976
977 sme_p2pSetPs(hHal, &NoA);
978 }
979 }
980 return status;
981}
982
983int hdd_setP2pPs( struct net_device *dev, void *msgData )
984{
985 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
986 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
987 VOS_STATUS status = VOS_STATUS_SUCCESS;
988 tP2pPsConfig NoA;
989 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
990
991 NoA.opp_ps = pappNoA->opp_ps;
992 NoA.ctWindow = pappNoA->ctWindow;
993 NoA.duration = pappNoA->duration;
994 NoA.interval = pappNoA->interval;
995 NoA.count = pappNoA->count;
996 NoA.single_noa_duration = pappNoA->single_noa_duration;
997 NoA.psSelection = pappNoA->psSelection;
998 NoA.sessionid = pAdapter->sessionId;
999
1000 sme_p2pSetPs(hHal, &NoA);
1001 return status;
1002}
1003#endif
1004
1005static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
1006{
1007 tANI_U8 sessionType;
1008
1009 switch( type )
1010 {
1011 case NL80211_IFTYPE_AP:
1012 sessionType = WLAN_HDD_SOFTAP;
1013 break;
1014 case NL80211_IFTYPE_P2P_GO:
1015 sessionType = WLAN_HDD_P2P_GO;
1016 break;
1017 case NL80211_IFTYPE_P2P_CLIENT:
1018 sessionType = WLAN_HDD_P2P_CLIENT;
1019 break;
1020 case NL80211_IFTYPE_STATION:
1021 sessionType = WLAN_HDD_INFRA_STATION;
1022 break;
1023 case NL80211_IFTYPE_MONITOR:
1024 sessionType = WLAN_HDD_MONITOR;
1025 break;
1026 default:
1027 sessionType = WLAN_HDD_INFRA_STATION;
1028 break;
1029 }
1030
1031 return sessionType;
1032}
1033
1034#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1035struct net_device* wlan_hdd_add_virtual_intf(
1036 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1037 u32 *flags, struct vif_params *params )
1038#else
1039int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
1040 enum nl80211_iftype type,
1041 u32 *flags, struct vif_params *params )
1042#endif
1043{
1044 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1045 hdd_adapter_t* pAdapter = NULL;
1046
1047 ENTER();
1048
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001049 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
1050 {
Jeff Johnsond13512a2012-07-17 11:42:19 -07001051 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001052 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -07001053 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001054 }
1055
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001056 if (pHddCtx->isLogpInProgress)
1057 {
1058 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1059 "%s:LOGP in Progress. Ignore!!!", __func__);
1060#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1061 return NULL;
1062#else
1063 return -EAGAIN;
1064#endif
1065 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001066 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
1067 {
1068 if( (NL80211_IFTYPE_P2P_GO == type) ||
1069 (NL80211_IFTYPE_P2P_CLIENT == type) )
1070 {
1071 /* Generate the P2P Interface Address. this address must be
1072 * different from the P2P Device Address.
1073 */
1074 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1075 p2pDeviceAddress.bytes[4] ^= 0x80;
1076 pAdapter = hdd_open_adapter( pHddCtx,
1077 wlan_hdd_get_session_type(type),
1078 name, p2pDeviceAddress.bytes,
1079 VOS_TRUE );
1080 }
1081 }
1082 else
1083 {
1084 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1085 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1086 }
1087
1088 if( NULL == pAdapter)
1089 {
1090 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1091#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1092 return NULL;
1093#else
1094 return -EINVAL;
1095#endif
1096 }
1097 EXIT();
1098#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1099 return pAdapter->dev;
1100#else
1101 return 0;
1102#endif
1103}
1104
1105int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
1106{
1107 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1108 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1109 ENTER();
1110
1111 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1112 __func__,pVirtAdapter->device_mode);
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001113 if (pHddCtx->isLogpInProgress)
1114 {
1115 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1116 "%s:LOGP in Progress. Ignore!!!", __func__);
1117 return -EAGAIN;
1118 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001119
1120 wlan_hdd_release_intf_addr( pHddCtx,
1121 pVirtAdapter->macAddressCurrent.bytes );
1122
1123 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1124 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1125 EXIT();
1126 return 0;
1127}
1128
1129void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
1130 tANI_U32 nFrameLength, tANI_U8* pbFrames,
1131 tANI_U8 frameType )
1132{
1133 //Indicate a Frame over Monitor Intf.
1134 int rxstat;
1135 struct sk_buff *skb = NULL;
1136 int needed_headroom = 0;
1137 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1138 HDD_RX_FLAG_MMIC_STRIPPED;
Jeff Johnsone7245742012-09-05 17:12:55 -07001139#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1140 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1141#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001142 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1143
1144 VOS_ASSERT( (pbFrames != NULL) );
1145
1146 /* room for the radiotap header based on driver features
1147 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1148 * RX flags.
1149 * */
1150 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1151
1152 //alloc skb here
1153 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1154 if (unlikely(NULL == skb))
1155 {
1156 hddLog( LOGW, FL("Unable to allocate skb"));
1157 return;
1158 }
1159 skb_reserve(skb, VPKT_SIZE_BUFFER);
1160 if (unlikely(skb_headroom(skb) < nFrameLength))
1161 {
1162 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1163 "HDD [%d]: Insufficient headroom, "
1164 "head[%p], data[%p], req[%d]",
1165 __LINE__, skb->head, skb->data, nFrameLength);
1166 kfree_skb(skb);
1167 return ;
1168 }
1169 // actually push the data
1170 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1171 /* prepend radiotap information */
1172 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1173 {
1174 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1175 //free skb
1176 kfree_skb(skb);
1177 return ;
1178 }
1179
1180 skb_reset_mac_header( skb );
1181 skb->dev = pMonAdapter->dev;
1182 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001183 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnsone7245742012-09-05 17:12:55 -07001184#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1185 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1186#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001187 rxstat = netif_rx_ni(skb);
1188 if( NET_RX_SUCCESS == rxstat )
1189 {
1190 hddLog( LOG1, FL("Success"));
1191 }
1192 else
1193 hddLog( LOGE, FL("Failed %d"), rxstat);
1194
1195 return ;
1196}
1197
1198void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1199 tANI_U32 nFrameLength,
1200 tANI_U8* pbFrames,
1201 tANI_U8 frameType,
1202 tANI_U32 rxChan )
1203{
1204 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001205 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001206 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001207 tActionFrmType actionFrmType;
1208 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001209
1210 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1211 __func__, frameType, nFrameLength);
1212
1213 if (NULL == pAdapter)
1214 {
1215 hddLog( LOGE, FL("pAdapter is NULL"));
1216 return;
1217 }
1218
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001219 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1220 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1221
1222 /* Get pAdapter from Destination mac address of the frame */
1223 if ((type == SIR_MAC_MGMT_FRAME) &&
1224 (subType != SIR_MAC_MGMT_PROBE_REQ))
1225 {
1226 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1227 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1228 if (NULL == pAdapter)
1229 {
1230 /* Under assumtion that we don't receive any action frame
1231 * with BCST as destination we dropping action frame
1232 */
Madan Mohan Koyyalamudi051ff0b2012-12-03 16:55:26 -08001233 hddLog(VOS_TRACE_LEVEL_FATAL,"pAdapter for action frame is NULL Macaddr = "
1234 MAC_ADDRESS_STR ,
1235 MAC_ADDR_ARRAY(&pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]));
1236 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Frame Type = %d Frame Length = %d"
1237 " subType = %d \n",__func__,frameType,nFrameLength,subType);
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001238 return;
1239 }
1240 }
1241
Jeff Johnson295189b2012-06-20 16:38:30 -07001242 if (NULL == pAdapter->dev)
1243 {
1244 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1245 return;
1246 }
1247
1248 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1249 {
1250 hddLog( LOGE, FL("pAdapter has invalid magic"));
1251 return;
1252 }
1253
1254 if( !nFrameLength )
1255 {
1256 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1257 return;
1258 }
1259
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001260 if (NULL == pbFrames) {
1261 hddLog( LOGE, FL("pbFrames is NULL"));
1262 return;
1263 }
1264
1265
Jeff Johnson295189b2012-06-20 16:38:30 -07001266 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1267 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1268 )
1269 {
1270 hdd_adapter_t *pMonAdapter =
1271 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1272
1273 if( NULL != pMonAdapter )
1274 {
1275 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1276 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1277 pbFrames, frameType);
1278 return;
1279 }
1280 }
1281
1282 //Channel indicated may be wrong. TODO
1283 //Indicate an action frame.
1284 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1285 {
1286 freq = ieee80211_channel_to_frequency( rxChan,
1287 IEEE80211_BAND_2GHZ);
1288 }
1289 else
1290 {
1291 freq = ieee80211_channel_to_frequency( rxChan,
1292 IEEE80211_BAND_5GHZ);
1293 }
1294
Jeff Johnsone7245742012-09-05 17:12:55 -07001295 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1296
1297 if ((type == SIR_MAC_MGMT_FRAME) &&
1298 (subType == SIR_MAC_MGMT_ACTION) &&
1299 (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
1300 {
1301 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1302 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001303#ifdef WLAN_FEATURE_P2P_DEBUG
1304 if(actionFrmType > MAX_P2P_ACTION_FRAME_TYPE)
1305 {
1306 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] <--- OTA",
1307 actionFrmType);
1308 }
1309 else
1310 {
1311 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s <--- OTA",
1312 p2p_action_frame_type[actionFrmType]);
1313 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
1314 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1315 {
1316 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
1317 hddLog(LOGE,"[P2P State]Inactive state to "
1318 "GO negotation progress state");
1319 }
1320 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1321 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
1322 {
1323 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1324 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
1325 " completed state");
1326 }
1327 else if( (actionFrmType == WLAN_HDD_INVITATION_REQ) &&
1328 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1329 {
1330 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1331 hddLog(LOGE,"[P2P State]Inactive state to GO nego"
1332 " completed state Autonomus GO fromation");
1333 }
1334 }
1335#endif
1336
Jeff Johnsone7245742012-09-05 17:12:55 -07001337 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1338 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1339 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1340 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1341 {
1342 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1343 __func__);
1344 hdd_sendActionCnf(pAdapter, TRUE);
1345 }
1346 }
1347
Jeff Johnson295189b2012-06-20 16:38:30 -07001348 //Indicate Frame Over Normal Interface
1349 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1350
1351#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
1352 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1353 pbFrames, nFrameLength,
1354 GFP_ATOMIC );
1355#else
1356 cfg80211_rx_mgmt( pAdapter->dev, freq,
1357 pbFrames, nFrameLength,
1358 GFP_ATOMIC );
1359#endif //LINUX_VERSION_CODE
1360}
1361
1362/*
1363 * ieee80211_add_rx_radiotap_header - add radiotap header
1364 */
1365static int hdd_wlan_add_rx_radiotap_hdr (
1366 struct sk_buff *skb, int rtap_len, int flag )
1367{
1368 u8 rtap_temp[20] = {0};
1369 struct ieee80211_radiotap_header *rthdr;
1370 unsigned char *pos;
1371 u16 rx_flags = 0;
1372
1373 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1374
1375 /* radiotap header, set always present flags */
1376 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1377 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1378 rthdr->it_len = cpu_to_le16(rtap_len);
1379
1380 pos = (unsigned char *) (rthdr + 1);
1381
1382 /* the order of the following fields is important */
1383
1384 /* IEEE80211_RADIOTAP_FLAGS */
1385 *pos = 0;
1386 pos++;
1387
1388 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1389 /* ensure 2 byte alignment for the 2 byte field as required */
1390 if ((pos - (u8 *)rthdr) & 1)
1391 pos++;
1392 put_unaligned_le16(rx_flags, pos);
1393 pos += 2;
1394
1395 // actually push the data
1396 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1397
1398 return 0;
1399}
1400
1401static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1402 hdd_cfg80211_state_t* cfgState,
1403 tANI_BOOLEAN actionSendSuccess )
1404{
1405 struct ieee80211_radiotap_header *rthdr;
1406 unsigned char *pos;
1407 struct sk_buff *skb = cfgState->skb;
Jeff Johnsone7245742012-09-05 17:12:55 -07001408#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1409 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1410#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001411
1412 /* 2 Byte for TX flags and 1 Byte for Retry count */
1413 u32 rtHdrLen = sizeof(*rthdr) + 3;
1414
1415 u8 *data;
1416
1417 /* We have to return skb with Data starting with MAC header. We have
1418 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1419 * entire skb->len from skb and then we will push cfgState->buf to skb
1420 * */
1421 if( NULL == skb_pull(skb, skb->len) )
1422 {
1423 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1424 kfree_skb(cfgState->skb);
1425 return;
1426 }
1427
1428 data = skb_push( skb, cfgState->len );
1429
1430 if (data == NULL)
1431 {
1432 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1433 kfree_skb( cfgState->skb );
1434 return;
1435 }
1436
1437 memcpy( data, cfgState->buf, cfgState->len );
1438
1439 /* send frame to monitor interfaces now */
1440 if( skb_headroom(skb) < rtHdrLen )
1441 {
1442 hddLog( LOGE, FL("No headroom for rtap header"));
1443 kfree_skb(cfgState->skb);
1444 return;
1445 }
1446
1447 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1448
1449 memset( rthdr, 0, rtHdrLen );
1450 rthdr->it_len = cpu_to_le16( rtHdrLen );
1451 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1452 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1453 );
1454
1455 pos = (unsigned char *)( rthdr+1 );
1456
1457 // Fill TX flags
1458 *pos = actionSendSuccess;
1459 pos += 2;
1460
1461 // Fill retry count
1462 *pos = 0;
1463 pos++;
1464
1465 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001466 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001467 skb->pkt_type = PACKET_OTHERHOST;
1468 skb->protocol = htons(ETH_P_802_2);
1469 memset( skb->cb, 0, sizeof( skb->cb ) );
Jeff Johnsone7245742012-09-05 17:12:55 -07001470#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1471 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1472#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001473 if (in_interrupt())
1474 netif_rx( skb );
1475 else
1476 netif_rx_ni( skb );
1477
1478 /* Enable Queues which we have disabled earlier */
1479 netif_tx_start_all_queues( pAdapter->dev );
1480
1481}
1482#endif // CONFIG_CFG80211