blob: 6d319c07b884d4754d073a877c0d2d2c1f0ca8aa [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
47extern struct net_device_ops net_ops_struct;
48
49static int hdd_wlan_add_rx_radiotap_hdr( struct sk_buff *skb,
50 int rtap_len, int flag );
51
52static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
53 hdd_cfg80211_state_t* cfgState,
54 tANI_BOOLEAN actionSendSuccess );
55
56static void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
57 tANI_U32 nFrameLength,
58 tANI_U8* pbFrames,
59 tANI_U8 frameType );
60
61#ifdef WLAN_FEATURE_P2P
62eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx,
63 eHalStatus status )
64{
65 hdd_adapter_t *pAdapter = (hdd_adapter_t*) pCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -070066 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
67 hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
68
69 if( pRemainChanCtx == NULL )
70 {
71 hddLog( LOGW,
72 "%s: No Rem on channel pending for which Rsp is received", __func__);
73 return eHAL_STATUS_SUCCESS;
74 }
75
76 hddLog( LOG1, "Received remain on channel rsp");
77
78 cfgState->remain_on_chan_ctx = NULL;
79
80 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
81 {
82 if( cfgState->buf )
83 {
84 hddLog( LOGP,
85 "%s: We need to receive yet an ack from one of tx packet",
86 __func__);
87 }
88 cfg80211_remain_on_channel_expired( pRemainChanCtx->dev,
89 pRemainChanCtx->cookie,
90 &pRemainChanCtx->chan,
91 pRemainChanCtx->chan_type, GFP_KERNEL );
92 }
93
94 vos_mem_free( pRemainChanCtx );
95
96 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -070097 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
98 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -070099 )
100 {
101 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700102 sme_DeregisterMgmtFrame(
103 hHal, sessionId,
104 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
105 NULL, 0 );
106 }
107 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
108 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
109 )
110 {
111 WLANSAP_DeRegisterMgmtFrame(
112 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
113 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
114 NULL, 0 );
115 }
116
117 complete(&pAdapter->cancel_rem_on_chan_var);
118 return eHAL_STATUS_SUCCESS;
119}
120
Jeff Johnson32d95a32012-09-10 13:15:23 -0700121static void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700122{
Jeff Johnson295189b2012-06-20 16:38:30 -0700123 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
124 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700125
Jeff Johnson32d95a32012-09-10 13:15:23 -0700126 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700127 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700128 hddLog( LOG1, "Cancel Existing Remain on Channel");
129
130 /* Wait till remain on channel ready indication before issuing cancel
131 * remain on channel request, otherwise if remain on channel not
132 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700133 * will be in unknown state.
134 */
135 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
136 msecs_to_jiffies(WAIT_REM_CHAN_READY));
137 if (!status)
138 {
139 hddLog( LOGE,
140 "%s: timeout waiting for remain on channel ready indication",
141 __func__);
142 }
143
144 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700145
Jeff Johnson295189b2012-06-20 16:38:30 -0700146 /* Issue abort remain on chan request to sme.
147 * The remain on channel callback will make sure the remain_on_chan
148 * expired event is sent.
149 */
150 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700151 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
152 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700153 )
154 {
155 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
156 pAdapter->sessionId );
157 }
158 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
159 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
160 )
161 {
162 WLANSAP_CancelRemainOnChannel(
163 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
164 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700165
Jeff Johnson32d95a32012-09-10 13:15:23 -0700166 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700167 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700168
169 if (!status)
170 {
171 hddLog( LOGE,
172 "%s: timeout waiting for cancel remain on channel ready indication",
173 __func__);
174 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700175 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700176}
177
178int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
179{
180 int status = 0;
181 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
182
183 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
184 {
185 //Cancel Existing Remain On Channel
186 //If no action frame is pending
187 if( cfgState->remain_on_chan_ctx != NULL)
188 {
189 //Check whether Action Frame is pending or not
190 if( cfgState->buf == NULL)
191 {
192 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
193 }
194 else
195 {
196 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
197 status = -EBUSY;
198 }
199 }
200 }
201 return status;
202}
203
204static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
205 struct net_device *dev,
206 struct ieee80211_channel *chan,
207 enum nl80211_channel_type channel_type,
208 unsigned int duration, u64 *cookie,
209 rem_on_channel_request_type_t request_type )
210{
211 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
212 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
213 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
214 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
215 __func__,pAdapter->device_mode);
216
217 hddLog( LOG1,
218 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
219 chan->hw_value, chan->center_freq, channel_type, duration );
220
221 //Cancel existing remain On Channel if any
222 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700223
Jeff Johnsone7245742012-09-05 17:12:55 -0700224 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700225 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700226 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700227 * channel requets when Load/Unload is in progress*/
228 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
229 {
230 hddLog( LOGE,
231 "%s: Wlan Load/Unload is in progress", __func__);
232 return -EBUSY;
233 }
234
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700235 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
236 {
237 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
238 "%s:LOGP in Progress. Ignore!!!", __func__);
239 return -EAGAIN;
240 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700241 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
242 if( NULL == pRemainChanCtx )
243 {
244 hddLog(VOS_TRACE_LEVEL_FATAL,
245 "%s: Not able to allocate memory for Channel context",
246 __func__);
247 return -ENOMEM;
248 }
249
250 vos_mem_copy( &pRemainChanCtx->chan, chan,
251 sizeof(struct ieee80211_channel) );
252
253 pRemainChanCtx->chan_type = channel_type;
254 pRemainChanCtx->duration = duration;
255 pRemainChanCtx->dev = dev;
256 *cookie = (tANI_U32) pRemainChanCtx;
257 pRemainChanCtx->cookie = *cookie;
258 pRemainChanCtx->rem_on_chan_request = request_type;
259 cfgState->remain_on_chan_ctx = pRemainChanCtx;
260 cfgState->current_freq = chan->center_freq;
261
262 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
263
264 //call sme API to start remain on channel.
265 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700266 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
267 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700268 )
269 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700270 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700271 //call sme API to start remain on channel.
272 sme_RemainOnChannel(
273 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
274 chan->hw_value, duration,
275 wlan_hdd_remain_on_channel_callback, pAdapter );
276
277 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
278 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
279 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
280
281 }
282 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
283 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
284 )
285 {
286 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700287 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700288 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
289 chan->hw_value, duration,
290 wlan_hdd_remain_on_channel_callback, pAdapter ))
291
292 {
293 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
294 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
295 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700296 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700297 return -EINVAL;
298 }
299
300
Jeff Johnson43971f52012-07-17 12:26:56 -0700301 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700302 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
303 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
304 NULL, 0 ))
305 {
306 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
307 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
308 WLANSAP_CancelRemainOnChannel(
309 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
310 return -EINVAL;
311 }
312
313 }
314 return 0;
315
316}
317
318int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
319 struct net_device *dev,
320 struct ieee80211_channel *chan,
321 enum nl80211_channel_type channel_type,
322 unsigned int duration, u64 *cookie )
323{
324 return wlan_hdd_request_remain_on_channel(wiphy, dev,
325 chan, channel_type, duration, cookie,
326 REMAIN_ON_CHANNEL_REQUEST);
327}
328
329void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
330{
331 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
332 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
333
334 hddLog( LOG1, "Ready on chan ind");
335
336 if( pRemainChanCtx != NULL )
337 {
338 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
339 {
340 cfg80211_ready_on_channel( pAdapter->dev, (tANI_U32)pRemainChanCtx,
341 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
342 pRemainChanCtx->duration, GFP_KERNEL );
343 }
344#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
345 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
346 {
347 complete(&pAdapter->offchannel_tx_event);
348 }
349#endif
350 complete(&pAdapter->rem_on_chan_ready_event);
351 }
352 else
353 {
354 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
355 }
356 return;
357}
358
359int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
360 struct net_device *dev, u64 cookie )
361{
362 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700363 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
364 int status = 0;
365
366 hddLog( LOG1, "Cancel remain on channel req");
367
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700368 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
369 {
370 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
371 "%s:LOGP in Progress. Ignore!!!", __func__);
372 return -EAGAIN;
373 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700374 /* FIXME cancel currently running remain on chan.
375 * Need to check cookie and cancel accordingly
376 */
377 if( (cfgState->remain_on_chan_ctx == NULL) ||
378 (cfgState->remain_on_chan_ctx->cookie != cookie) )
379 {
380 hddLog( LOGE,
381 "%s: No Remain on channel pending with specified cookie value",
382 __func__);
383 return -EINVAL;
384 }
385
386 /* wait until remain on channel ready event received
387 * for already issued remain on channel request */
388 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
389 msecs_to_jiffies(WAIT_REM_CHAN_READY));
390 if (!status)
391 {
392 hddLog( LOGE,
393 "%s: timeout waiting for remain on channel ready indication",
394 __func__);
395 }
396 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
397 /* Issue abort remain on chan request to sme.
398 * The remain on channel callback will make sure the remain_on_chan
399 * expired event is sent.
400 */
401 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700402 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
403 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700404 )
405 {
406 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700407 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
408 sessionId );
409 }
410 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
411 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
412 )
413 {
414 WLANSAP_CancelRemainOnChannel(
415 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
416 }
417 else
418 {
419 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
420 __func__, pAdapter->device_mode);
421 return -EIO;
422 }
423 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
424 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
425 return 0;
426}
427
428#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
429int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
430 struct ieee80211_channel *chan, bool offchan,
431 enum nl80211_channel_type channel_type,
432 bool channel_type_valid, unsigned int wait,
433 const u8 *buf, size_t len, bool no_cck,
434 bool dont_wait_for_ack, u64 *cookie )
435#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
436int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
437 struct ieee80211_channel *chan, bool offchan,
438 enum nl80211_channel_type channel_type,
439 bool channel_type_valid, unsigned int wait,
440 const u8 *buf, size_t len, u64 *cookie )
441#else
442int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
443 struct ieee80211_channel *chan,
444 enum nl80211_channel_type channel_type,
445 bool channel_type_valid,
446 const u8 *buf, size_t len, u64 *cookie )
447#endif //LINUX_VERSION_CODE
448{
449 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
450 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700451 tANI_U16 extendedWait = 0;
452 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
453 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
454 tActionFrmType actionFrmType;
455 bool noack = 0;
456
Jeff Johnson295189b2012-06-20 16:38:30 -0700457#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
458 hdd_adapter_t *goAdapter;
459#endif
460
Jeff Johnsone7245742012-09-05 17:12:55 -0700461#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
462 noack = dont_wait_for_ack;
463#endif
464
465 //If the wait is coming as 0 with off channel set
466 //then set the wait to 200 ms
467 if (offchan && !wait)
468 wait = ACTION_FRAME_DEFAULT_WAIT;
469
Jeff Johnson295189b2012-06-20 16:38:30 -0700470 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
471 __func__,pAdapter->device_mode);
472
473 //Call sme API to send out a action frame.
474 // OR can we send it directly through data path??
475 // After tx completion send tx status back.
476 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
477 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
478 )
479 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700480 if (type == SIR_MAC_MGMT_FRAME)
481 {
482 if (subType == SIR_MAC_MGMT_PROBE_RSP)
483 {
484 /* Drop Probe response recieved from supplicant, as for GO and
485 SAP PE itself sends probe response
486 */
487 goto err_rem_channel;
488 }
489 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
490 (subType == SIR_MAC_MGMT_DEAUTH))
491 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700492 /* During EAP failure or P2P Group Remove supplicant
493 * is sending del_station command to driver. From
494 * del_station function, Driver will send deauth frame to
495 * p2p client. No need to send disassoc frame from here.
496 * so Drop the frame here and send tx indication back to
497 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700498 */
499 tANI_U8 dstMac[ETH_ALEN] = {0};
500 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700501 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700502 "%s: Deauth/Disassoc received for STA:"
Jeff Johnsone7245742012-09-05 17:12:55 -0700503 "%02x:%02x:%02x:%02x:%02x:%02x",
504 __func__,
505 dstMac[0], dstMac[1], dstMac[2],
Jeff Johnson295189b2012-06-20 16:38:30 -0700506 dstMac[3], dstMac[4], dstMac[5]);
Jeff Johnson295189b2012-06-20 16:38:30 -0700507 goto err_rem_channel;
508 }
509 }
510 }
511
512 if( NULL != cfgState->buf )
513 return -EBUSY;
514
515 hddLog( LOG1, "Action frame tx request");
516
517#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
518 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
519
520 //If GO adapter exists and operating on same frequency
521 //then we will not request remain on channel
522 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
523 == goAdapter->sessionCtx.ap.operatingChannel ) )
524 {
525 goto send_frame;
526 }
527#endif
528
529#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
530 if( offchan && wait)
531 {
532 int status;
533
534 // In case of P2P Client mode if we are already
535 // on the same channel then send the frame directly
536
537 if((cfgState->remain_on_chan_ctx != NULL) &&
538 (cfgState->current_freq == chan->center_freq)
539 )
540 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700541 hddLog(LOG1,"action frame: extending the wait time\n");
542 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700543 goto send_frame;
544 }
545
546 INIT_COMPLETION(pAdapter->offchannel_tx_event);
547
548 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
549 chan, channel_type, wait, cookie,
550 OFF_CHANNEL_ACTION_TX);
551
552 if(0 != status)
553 {
554 if( (-EBUSY == status) &&
555 (cfgState->current_freq == chan->center_freq) )
556 {
557 goto send_frame;
558 }
559 goto err_rem_channel;
560 }
561
562 /* Wait for driver to be ready on the requested channel */
563 status = wait_for_completion_interruptible_timeout(
564 &pAdapter->offchannel_tx_event,
565 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
566 if(!status)
567 {
568 hddLog( LOGE, "Not able to complete remain on channel request"
569 " within timeout period");
570 goto err_rem_channel;
571 }
572 }
573 else if ( offchan )
574 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700575 /* Check before sending action frame
576 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700577 if(NULL == cfgState->remain_on_chan_ctx)
578 {
579 goto err_rem_channel;
580 }
581 }
582 send_frame:
583#endif
584
Jeff Johnsone7245742012-09-05 17:12:55 -0700585 if(!noack)
586 {
587 cfgState->buf = vos_mem_malloc( len ); //buf;
588 if( cfgState->buf == NULL )
589 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700590
Jeff Johnsone7245742012-09-05 17:12:55 -0700591 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700592
Jeff Johnsone7245742012-09-05 17:12:55 -0700593 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700594
595#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700596 if( cfgState->remain_on_chan_ctx )
597 {
598 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
599 *cookie = cfgState->action_cookie;
600 }
601 else
602 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700603#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700604 *cookie = (tANI_U32) cfgState->buf;
605 cfgState->action_cookie = *cookie;
Jeff Johnson295189b2012-06-20 16:38:30 -0700606#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700607 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700608#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700609 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700610
611 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700612 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
613 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700614 )
615 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700616 tANI_U8 sessionId = pAdapter->sessionId;
617 if ((type == SIR_MAC_MGMT_FRAME) &&
618 (subType == SIR_MAC_MGMT_ACTION) &&
619 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700620 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700621 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
622 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
623 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700624 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700625 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
626 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
627 }
628 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
629 {
630 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
631 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700632 }
633 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700634
Jeff Johnson295189b2012-06-20 16:38:30 -0700635 if (eHAL_STATUS_SUCCESS !=
636 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700637 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700638 {
639 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
640 "%s: sme_sendAction returned fail", __func__);
641 goto err;
642 }
643 }
644 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
645 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
646 )
647 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700648 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700649 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700650 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700651 {
652 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
653 "%s: WLANSAP_SendAction returned fail", __func__);
654 goto err;
655 }
656 }
657
658 return 0;
659err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700660 if(!noack)
661 {
662 hdd_sendActionCnf( pAdapter, FALSE );
663 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700664 return 0;
665err_rem_channel:
666 *cookie = (tANI_U32)cfgState;
667 cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL );
668 return 0;
669}
670
671#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
672int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
673 struct net_device *dev,
674 u64 cookie)
675{
676 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
677}
678#endif
679
680void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
681{
682 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
683
Jeff Johnsone7245742012-09-05 17:12:55 -0700684 cfgState->actionFrmState = HDD_IDLE;
685
Jeff Johnson295189b2012-06-20 16:38:30 -0700686 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
687 if( NULL == cfgState->buf )
688 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700689 return;
690 }
691
692 /* If skb is NULL it means this packet was received on CFG80211 interface
693 * else it was received on Monitor interface */
694 if( cfgState->skb == NULL )
695 {
696 /*
697 * buf is the same pointer it passed us to send. Since we are sending
698 * it through control path, we use different buffers.
699 * In case of mac80211, they just push it to the skb and pass the same
700 * data while sending tx ack status.
701 * */
702 cfg80211_mgmt_tx_status( pAdapter->dev, cfgState->action_cookie,
703 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
704 vos_mem_free( cfgState->buf );
705 cfgState->buf = NULL;
706 }
707 else
708 {
709 hdd_adapter_t* pMonAdapter =
710 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
711 if( pMonAdapter == NULL )
712 {
713 hddLog( LOGE, "Not able to get Monitor Adapter");
714 cfgState->skb = NULL;
715 vos_mem_free( cfgState->buf );
716 cfgState->buf = NULL;
717 complete(&pAdapter->tx_action_cnf_event);
718 return;
719 }
720 /* Send TX completion feedback over monitor interface. */
721 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
722 cfgState->skb = NULL;
723 vos_mem_free( cfgState->buf );
724 cfgState->buf = NULL;
725 /* Look for the next Mgmt packet to TX */
726 hdd_mon_tx_mgmt_pkt(pAdapter);
727 }
728 complete(&pAdapter->tx_action_cnf_event);
729}
730
731/**
732 * hdd_setP2pNoa
733 *
734 *FUNCTION:
735 * This function is called from hdd_hostapd_ioctl function when Driver
736 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
737 *
738 *LOGIC:
739 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
740 *
741 *ASSUMPTIONS:
742 *
743 *
744 *NOTE:
745 *
746 * @param dev Pointer to net device structure
747 * @param command Pointer to command
748 *
749 * @return Status
750 */
751
752int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
753{
754 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
755 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
756 VOS_STATUS status = VOS_STATUS_SUCCESS;
757 tP2pPsConfig NoA;
758 int count, duration, interval;
759 char *param;
760
761 param = strchr(command, ' ');
762 if (param == NULL)
763 return -1;
764 param++;
765 sscanf(param, "%d %d %d", &count, &duration, &interval);
766 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
767 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
768 __func__, count, duration, interval);
769
770 /* PS Selection
771 * Periodic NoA (2)
772 * Single NOA (4)
773 */
774 NoA.opp_ps = 0;
775 NoA.ctWindow = 0;
776 if (count == 1)
777 {
778 NoA.duration = 0;
779 NoA.single_noa_duration = duration;
780 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
781 }
782 else
783 {
784 NoA.duration = duration;
785 NoA.single_noa_duration = 0;
786 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
787 }
788 NoA.interval = interval;
789 NoA.count = count;
790 NoA.sessionid = pAdapter->sessionId;
791
792 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
793 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
794 "interval %d count %d single noa duration %d "
795 "PsSelection %x \n", __func__, NoA.opp_ps,
796 NoA.ctWindow, NoA.duration, NoA.interval,
797 NoA.count, NoA.single_noa_duration,
798 NoA.psSelection);
799
800 sme_p2pSetPs(hHal, &NoA);
801 return status;
802}
803
804/**
805 * hdd_setP2pOpps
806 *
807 *FUNCTION:
808 * This function is called from hdd_hostapd_ioctl function when Driver
809 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
810 *
811 *LOGIC:
812 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
813 *
814 *ASSUMPTIONS:
815 *
816 *
817 *NOTE:
818 *
819 * @param dev Pointer to net device structure
820 * @param command Pointer to command
821 *
822 * @return Status
823 */
824
825int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
826{
827 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
828 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
829 VOS_STATUS status = VOS_STATUS_SUCCESS;
830 tP2pPsConfig NoA;
831 char *param;
832 int legacy_ps, opp_ps, ctwindow;
833
834 param = strchr(command, ' ');
835 if (param == NULL)
836 return -1;
837 param++;
838 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
839 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
840 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
841 __func__, legacy_ps, opp_ps, ctwindow);
842
843 /* PS Selection
844 * Opportunistic Power Save (1)
845 */
846
847 /* From wpa_cli user need to use separate command to set ctWindow and Opps
848 * When user want to set ctWindow during that time other parameters
849 * values are coming from wpa_supplicant as -1.
850 * Example : User want to set ctWindow with 30 then wpa_cli command :
851 * P2P_SET ctwindow 30
852 * Command Received at hdd_hostapd_ioctl is as below:
853 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
854 */
855 if (ctwindow != -1)
856 {
857
858 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
859 "Opportunistic Power Save is %s \n",
860 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
861
862 if (ctwindow != pAdapter->ctw)
863 {
864 pAdapter->ctw = ctwindow;
865
866 if(pAdapter->ops)
867 {
868 NoA.opp_ps = pAdapter->ops;
869 NoA.ctWindow = pAdapter->ctw;
870 NoA.duration = 0;
871 NoA.single_noa_duration = 0;
872 NoA.interval = 0;
873 NoA.count = 0;
874 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
875 NoA.sessionid = pAdapter->sessionId;
876
877 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
878 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
879 "interval %d count %d single noa duration %d "
880 "PsSelection %x \n", __func__, NoA.opp_ps,
881 NoA.ctWindow, NoA.duration, NoA.interval,
882 NoA.count, NoA.single_noa_duration,
883 NoA.psSelection);
884
885 sme_p2pSetPs(hHal, &NoA);
886 }
887 return 0;
888 }
889 }
890
891 if (opp_ps != -1)
892 {
893 pAdapter->ops = opp_ps;
894
895 if ((opp_ps != -1) && (pAdapter->ctw))
896 {
897 NoA.opp_ps = opp_ps;
898 NoA.ctWindow = pAdapter->ctw;
899 NoA.duration = 0;
900 NoA.single_noa_duration = 0;
901 NoA.interval = 0;
902 NoA.count = 0;
903 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
904 NoA.sessionid = pAdapter->sessionId;
905
906 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
907 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
908 "interval %d count %d single noa duration %d "
909 "PsSelection %x \n", __func__, NoA.opp_ps,
910 NoA.ctWindow, NoA.duration, NoA.interval,
911 NoA.count, NoA.single_noa_duration,
912 NoA.psSelection);
913
914 sme_p2pSetPs(hHal, &NoA);
915 }
916 }
917 return status;
918}
919
920int hdd_setP2pPs( struct net_device *dev, void *msgData )
921{
922 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
923 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
924 VOS_STATUS status = VOS_STATUS_SUCCESS;
925 tP2pPsConfig NoA;
926 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
927
928 NoA.opp_ps = pappNoA->opp_ps;
929 NoA.ctWindow = pappNoA->ctWindow;
930 NoA.duration = pappNoA->duration;
931 NoA.interval = pappNoA->interval;
932 NoA.count = pappNoA->count;
933 NoA.single_noa_duration = pappNoA->single_noa_duration;
934 NoA.psSelection = pappNoA->psSelection;
935 NoA.sessionid = pAdapter->sessionId;
936
937 sme_p2pSetPs(hHal, &NoA);
938 return status;
939}
940#endif
941
942static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
943{
944 tANI_U8 sessionType;
945
946 switch( type )
947 {
948 case NL80211_IFTYPE_AP:
949 sessionType = WLAN_HDD_SOFTAP;
950 break;
951 case NL80211_IFTYPE_P2P_GO:
952 sessionType = WLAN_HDD_P2P_GO;
953 break;
954 case NL80211_IFTYPE_P2P_CLIENT:
955 sessionType = WLAN_HDD_P2P_CLIENT;
956 break;
957 case NL80211_IFTYPE_STATION:
958 sessionType = WLAN_HDD_INFRA_STATION;
959 break;
960 case NL80211_IFTYPE_MONITOR:
961 sessionType = WLAN_HDD_MONITOR;
962 break;
963 default:
964 sessionType = WLAN_HDD_INFRA_STATION;
965 break;
966 }
967
968 return sessionType;
969}
970
971#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
972struct net_device* wlan_hdd_add_virtual_intf(
973 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
974 u32 *flags, struct vif_params *params )
975#else
976int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
977 enum nl80211_iftype type,
978 u32 *flags, struct vif_params *params )
979#endif
980{
981 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
982 hdd_adapter_t* pAdapter = NULL;
983
984 ENTER();
985
Jeff Johnson04dd8a82012-06-29 20:41:40 -0700986 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
987 {
Jeff Johnsond13512a2012-07-17 11:42:19 -0700988 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -0700989 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -0700990 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -0700991 }
992
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700993 if (pHddCtx->isLogpInProgress)
994 {
995 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
996 "%s:LOGP in Progress. Ignore!!!", __func__);
997#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
998 return NULL;
999#else
1000 return -EAGAIN;
1001#endif
1002 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001003 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
1004 {
1005 if( (NL80211_IFTYPE_P2P_GO == type) ||
1006 (NL80211_IFTYPE_P2P_CLIENT == type) )
1007 {
1008 /* Generate the P2P Interface Address. this address must be
1009 * different from the P2P Device Address.
1010 */
1011 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1012 p2pDeviceAddress.bytes[4] ^= 0x80;
1013 pAdapter = hdd_open_adapter( pHddCtx,
1014 wlan_hdd_get_session_type(type),
1015 name, p2pDeviceAddress.bytes,
1016 VOS_TRUE );
1017 }
1018 }
1019 else
1020 {
1021 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1022 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1023 }
1024
1025 if( NULL == pAdapter)
1026 {
1027 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1028#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1029 return NULL;
1030#else
1031 return -EINVAL;
1032#endif
1033 }
1034 EXIT();
1035#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1036 return pAdapter->dev;
1037#else
1038 return 0;
1039#endif
1040}
1041
1042int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
1043{
1044 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1045 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1046 ENTER();
1047
1048 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1049 __func__,pVirtAdapter->device_mode);
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 return -EAGAIN;
1055 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001056
1057 wlan_hdd_release_intf_addr( pHddCtx,
1058 pVirtAdapter->macAddressCurrent.bytes );
1059
1060 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1061 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1062 EXIT();
1063 return 0;
1064}
1065
1066void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
1067 tANI_U32 nFrameLength, tANI_U8* pbFrames,
1068 tANI_U8 frameType )
1069{
1070 //Indicate a Frame over Monitor Intf.
1071 int rxstat;
1072 struct sk_buff *skb = NULL;
1073 int needed_headroom = 0;
1074 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1075 HDD_RX_FLAG_MMIC_STRIPPED;
Jeff Johnsone7245742012-09-05 17:12:55 -07001076#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1077 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1078#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001079 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1080
1081 VOS_ASSERT( (pbFrames != NULL) );
1082
1083 /* room for the radiotap header based on driver features
1084 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1085 * RX flags.
1086 * */
1087 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1088
1089 //alloc skb here
1090 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1091 if (unlikely(NULL == skb))
1092 {
1093 hddLog( LOGW, FL("Unable to allocate skb"));
1094 return;
1095 }
1096 skb_reserve(skb, VPKT_SIZE_BUFFER);
1097 if (unlikely(skb_headroom(skb) < nFrameLength))
1098 {
1099 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1100 "HDD [%d]: Insufficient headroom, "
1101 "head[%p], data[%p], req[%d]",
1102 __LINE__, skb->head, skb->data, nFrameLength);
1103 kfree_skb(skb);
1104 return ;
1105 }
1106 // actually push the data
1107 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1108 /* prepend radiotap information */
1109 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1110 {
1111 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1112 //free skb
1113 kfree_skb(skb);
1114 return ;
1115 }
1116
1117 skb_reset_mac_header( skb );
1118 skb->dev = pMonAdapter->dev;
1119 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001120 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnsone7245742012-09-05 17:12:55 -07001121#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1122 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1123#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001124 rxstat = netif_rx_ni(skb);
1125 if( NET_RX_SUCCESS == rxstat )
1126 {
1127 hddLog( LOG1, FL("Success"));
1128 }
1129 else
1130 hddLog( LOGE, FL("Failed %d"), rxstat);
1131
1132 return ;
1133}
1134
1135void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1136 tANI_U32 nFrameLength,
1137 tANI_U8* pbFrames,
1138 tANI_U8 frameType,
1139 tANI_U32 rxChan )
1140{
1141 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001142 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001143 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001144 tActionFrmType actionFrmType;
1145 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001146
1147 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1148 __func__, frameType, nFrameLength);
1149
1150 if (NULL == pAdapter)
1151 {
1152 hddLog( LOGE, FL("pAdapter is NULL"));
1153 return;
1154 }
1155
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001156 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1157 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1158
1159 /* Get pAdapter from Destination mac address of the frame */
1160 if ((type == SIR_MAC_MGMT_FRAME) &&
1161 (subType != SIR_MAC_MGMT_PROBE_REQ))
1162 {
1163 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1164 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1165 if (NULL == pAdapter)
1166 {
1167 /* Under assumtion that we don't receive any action frame
1168 * with BCST as destination we dropping action frame
1169 */
1170 VOS_ASSERT(0);
1171 hddLog( LOGP, FL("pAdapter for action frame is NULL"));
1172 return;
1173 }
1174 }
1175
Jeff Johnson295189b2012-06-20 16:38:30 -07001176 if (NULL == pAdapter->dev)
1177 {
1178 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1179 return;
1180 }
1181
1182 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1183 {
1184 hddLog( LOGE, FL("pAdapter has invalid magic"));
1185 return;
1186 }
1187
1188 if( !nFrameLength )
1189 {
1190 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1191 return;
1192 }
1193
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001194 if (NULL == pbFrames) {
1195 hddLog( LOGE, FL("pbFrames is NULL"));
1196 return;
1197 }
1198
1199
Jeff Johnson295189b2012-06-20 16:38:30 -07001200 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1201 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1202 )
1203 {
1204 hdd_adapter_t *pMonAdapter =
1205 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1206
1207 if( NULL != pMonAdapter )
1208 {
1209 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1210 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1211 pbFrames, frameType);
1212 return;
1213 }
1214 }
1215
1216 //Channel indicated may be wrong. TODO
1217 //Indicate an action frame.
1218 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1219 {
1220 freq = ieee80211_channel_to_frequency( rxChan,
1221 IEEE80211_BAND_2GHZ);
1222 }
1223 else
1224 {
1225 freq = ieee80211_channel_to_frequency( rxChan,
1226 IEEE80211_BAND_5GHZ);
1227 }
1228
Jeff Johnsone7245742012-09-05 17:12:55 -07001229 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1230
1231 if ((type == SIR_MAC_MGMT_FRAME) &&
1232 (subType == SIR_MAC_MGMT_ACTION) &&
1233 (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
1234 {
1235 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1236 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
1237 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1238 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1239 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1240 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1241 {
1242 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1243 __func__);
1244 hdd_sendActionCnf(pAdapter, TRUE);
1245 }
1246 }
1247
Jeff Johnson295189b2012-06-20 16:38:30 -07001248 //Indicate Frame Over Normal Interface
1249 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1250
1251#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
1252 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1253 pbFrames, nFrameLength,
1254 GFP_ATOMIC );
1255#else
1256 cfg80211_rx_mgmt( pAdapter->dev, freq,
1257 pbFrames, nFrameLength,
1258 GFP_ATOMIC );
1259#endif //LINUX_VERSION_CODE
1260}
1261
1262/*
1263 * ieee80211_add_rx_radiotap_header - add radiotap header
1264 */
1265static int hdd_wlan_add_rx_radiotap_hdr (
1266 struct sk_buff *skb, int rtap_len, int flag )
1267{
1268 u8 rtap_temp[20] = {0};
1269 struct ieee80211_radiotap_header *rthdr;
1270 unsigned char *pos;
1271 u16 rx_flags = 0;
1272
1273 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1274
1275 /* radiotap header, set always present flags */
1276 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1277 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1278 rthdr->it_len = cpu_to_le16(rtap_len);
1279
1280 pos = (unsigned char *) (rthdr + 1);
1281
1282 /* the order of the following fields is important */
1283
1284 /* IEEE80211_RADIOTAP_FLAGS */
1285 *pos = 0;
1286 pos++;
1287
1288 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1289 /* ensure 2 byte alignment for the 2 byte field as required */
1290 if ((pos - (u8 *)rthdr) & 1)
1291 pos++;
1292 put_unaligned_le16(rx_flags, pos);
1293 pos += 2;
1294
1295 // actually push the data
1296 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1297
1298 return 0;
1299}
1300
1301static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1302 hdd_cfg80211_state_t* cfgState,
1303 tANI_BOOLEAN actionSendSuccess )
1304{
1305 struct ieee80211_radiotap_header *rthdr;
1306 unsigned char *pos;
1307 struct sk_buff *skb = cfgState->skb;
Jeff Johnsone7245742012-09-05 17:12:55 -07001308#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1309 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1310#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001311
1312 /* 2 Byte for TX flags and 1 Byte for Retry count */
1313 u32 rtHdrLen = sizeof(*rthdr) + 3;
1314
1315 u8 *data;
1316
1317 /* We have to return skb with Data starting with MAC header. We have
1318 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1319 * entire skb->len from skb and then we will push cfgState->buf to skb
1320 * */
1321 if( NULL == skb_pull(skb, skb->len) )
1322 {
1323 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1324 kfree_skb(cfgState->skb);
1325 return;
1326 }
1327
1328 data = skb_push( skb, cfgState->len );
1329
1330 if (data == NULL)
1331 {
1332 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1333 kfree_skb( cfgState->skb );
1334 return;
1335 }
1336
1337 memcpy( data, cfgState->buf, cfgState->len );
1338
1339 /* send frame to monitor interfaces now */
1340 if( skb_headroom(skb) < rtHdrLen )
1341 {
1342 hddLog( LOGE, FL("No headroom for rtap header"));
1343 kfree_skb(cfgState->skb);
1344 return;
1345 }
1346
1347 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1348
1349 memset( rthdr, 0, rtHdrLen );
1350 rthdr->it_len = cpu_to_le16( rtHdrLen );
1351 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1352 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1353 );
1354
1355 pos = (unsigned char *)( rthdr+1 );
1356
1357 // Fill TX flags
1358 *pos = actionSendSuccess;
1359 pos += 2;
1360
1361 // Fill retry count
1362 *pos = 0;
1363 pos++;
1364
1365 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001366 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001367 skb->pkt_type = PACKET_OTHERHOST;
1368 skb->protocol = htons(ETH_P_802_2);
1369 memset( skb->cb, 0, sizeof( skb->cb ) );
Jeff Johnsone7245742012-09-05 17:12:55 -07001370#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1371 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1372#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001373 if (in_interrupt())
1374 netif_rx( skb );
1375 else
1376 netif_rx_ni( skb );
1377
1378 /* Enable Queues which we have disabled earlier */
1379 netif_tx_start_all_queues( pAdapter->dev );
1380
1381}
1382#endif // CONFIG_CFG80211