blob: 1b4f23b47f3879399b60eb8796b109404d833ff1 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
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;
66 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
67 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
68 hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
69
70 if( pRemainChanCtx == NULL )
71 {
72 hddLog( LOGW,
73 "%s: No Rem on channel pending for which Rsp is received", __func__);
74 return eHAL_STATUS_SUCCESS;
75 }
76
77 hddLog( LOG1, "Received remain on channel rsp");
78
79 cfgState->remain_on_chan_ctx = NULL;
80
81 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
82 {
83 if( cfgState->buf )
84 {
85 hddLog( LOGP,
86 "%s: We need to receive yet an ack from one of tx packet",
87 __func__);
88 }
89 cfg80211_remain_on_channel_expired( pRemainChanCtx->dev,
90 pRemainChanCtx->cookie,
91 &pRemainChanCtx->chan,
92 pRemainChanCtx->chan_type, GFP_KERNEL );
93 }
94
95 vos_mem_free( pRemainChanCtx );
96
97 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
98 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode )
99 )
100 {
101 tANI_U8 sessionId = pAdapter->sessionId;
102 if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
103 {
104 if ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode )
105 sessionId = pAdapter->p2pSessionId;
106 }
107 sme_DeregisterMgmtFrame(
108 hHal, sessionId,
109 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
110 NULL, 0 );
111 }
112 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
113 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
114 )
115 {
116 WLANSAP_DeRegisterMgmtFrame(
117 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
118 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
119 NULL, 0 );
120 }
121
122 complete(&pAdapter->cancel_rem_on_chan_var);
123 return eHAL_STATUS_SUCCESS;
124}
125
126static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
127 struct net_device *dev,
128 struct ieee80211_channel *chan,
129 enum nl80211_channel_type channel_type,
130 unsigned int duration, u64 *cookie,
131 rem_on_channel_request_type_t request_type )
132{
133 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
134 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
135 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
136 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
137 int status = 0;
138 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
139 __func__,pAdapter->device_mode);
140
141 hddLog( LOG1,
142 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
143 chan->hw_value, chan->center_freq, channel_type, duration );
144
145 if( cfgState->remain_on_chan_ctx != NULL)
146 {
147 /* Wait till remain on channel ready indication before issuing cancel
148 * remain on channel request, otherwise if remain on channel not
149 * received and if the driver issues cancel remain on channel then lim
150 * will be in unknown state.
151 */
152 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
153 msecs_to_jiffies(WAIT_REM_CHAN_READY));
154 if (!status)
155 {
156 hddLog( LOGE,
157 "%s: timeout waiting for remain on channel ready indication",
158 __func__);
159 }
160
161 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
162
163 /* Issue abort remain on chan request to sme.
164 * The remain on channel callback will make sure the remain_on_chan
165 * expired event is sent.
166 */
167 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
168 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode )
169 )
170 {
171 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
172 pAdapter->sessionId );
173 }
174 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
175 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
176 )
177 {
178 WLANSAP_CancelRemainOnChannel(
179 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
180 }
181
182 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
183 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
184 }
185
186 /* When P2P-GO and if we are trying to unload the driver then
187 * wlan driver is keep on receiving the remain on channel command
188 * and which is resulting in crash. So not allowing any remain on
189 * channel requets when Load/Unload is in progress*/
190 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
191 {
192 hddLog( LOGE,
193 "%s: Wlan Load/Unload is in progress", __func__);
194 return -EBUSY;
195 }
196
197 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
198 if( NULL == pRemainChanCtx )
199 {
200 hddLog(VOS_TRACE_LEVEL_FATAL,
201 "%s: Not able to allocate memory for Channel context",
202 __func__);
203 return -ENOMEM;
204 }
205
206 vos_mem_copy( &pRemainChanCtx->chan, chan,
207 sizeof(struct ieee80211_channel) );
208
209 pRemainChanCtx->chan_type = channel_type;
210 pRemainChanCtx->duration = duration;
211 pRemainChanCtx->dev = dev;
212 *cookie = (tANI_U32) pRemainChanCtx;
213 pRemainChanCtx->cookie = *cookie;
214 pRemainChanCtx->rem_on_chan_request = request_type;
215 cfgState->remain_on_chan_ctx = pRemainChanCtx;
216 cfgState->current_freq = chan->center_freq;
217
218 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
219
220 //call sme API to start remain on channel.
221 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
222 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode )
223 )
224 {
225 tANI_U8 sessionId = pAdapter->sessionId;
226 if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
227 {
228 if ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode )
229 sessionId = pAdapter->p2pSessionId;
230 }
231 //call sme API to start remain on channel.
232 sme_RemainOnChannel(
233 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
234 chan->hw_value, duration,
235 wlan_hdd_remain_on_channel_callback, pAdapter );
236
237 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
238 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
239 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
240
241 }
242 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
243 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
244 )
245 {
246 //call sme API to start remain on channel.
247 if (eHAL_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
248 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
249 chan->hw_value, duration,
250 wlan_hdd_remain_on_channel_callback, pAdapter ))
251
252 {
253 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
254 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
255 cfgState->remain_on_chan_ctx = NULL;
256 vos_mem_free (pRemainChanCtx);
257 return -EINVAL;
258 }
259
260
261 if (eHAL_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
262 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
263 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
264 NULL, 0 ))
265 {
266 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
267 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
268 WLANSAP_CancelRemainOnChannel(
269 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
270 return -EINVAL;
271 }
272
273 }
274 return 0;
275
276}
277
278int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
279 struct net_device *dev,
280 struct ieee80211_channel *chan,
281 enum nl80211_channel_type channel_type,
282 unsigned int duration, u64 *cookie )
283{
284 return wlan_hdd_request_remain_on_channel(wiphy, dev,
285 chan, channel_type, duration, cookie,
286 REMAIN_ON_CHANNEL_REQUEST);
287}
288
289void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
290{
291 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
292 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
293
294 hddLog( LOG1, "Ready on chan ind");
295
296 if( pRemainChanCtx != NULL )
297 {
298 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
299 {
300 cfg80211_ready_on_channel( pAdapter->dev, (tANI_U32)pRemainChanCtx,
301 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
302 pRemainChanCtx->duration, GFP_KERNEL );
303 }
304#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
305 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
306 {
307 complete(&pAdapter->offchannel_tx_event);
308 }
309#endif
310 complete(&pAdapter->rem_on_chan_ready_event);
311 }
312 else
313 {
314 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
315 }
316 return;
317}
318
319int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
320 struct net_device *dev, u64 cookie )
321{
322 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
323 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
324 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
325 int status = 0;
326
327 hddLog( LOG1, "Cancel remain on channel req");
328
329 /* FIXME cancel currently running remain on chan.
330 * Need to check cookie and cancel accordingly
331 */
332 if( (cfgState->remain_on_chan_ctx == NULL) ||
333 (cfgState->remain_on_chan_ctx->cookie != cookie) )
334 {
335 hddLog( LOGE,
336 "%s: No Remain on channel pending with specified cookie value",
337 __func__);
338 return -EINVAL;
339 }
340
341 /* wait until remain on channel ready event received
342 * for already issued remain on channel request */
343 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
344 msecs_to_jiffies(WAIT_REM_CHAN_READY));
345 if (!status)
346 {
347 hddLog( LOGE,
348 "%s: timeout waiting for remain on channel ready indication",
349 __func__);
350 }
351 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
352 /* Issue abort remain on chan request to sme.
353 * The remain on channel callback will make sure the remain_on_chan
354 * expired event is sent.
355 */
356 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
357 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode )
358 )
359 {
360 tANI_U8 sessionId = pAdapter->sessionId;
361 if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
362 {
363 if ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode )
364 sessionId = pAdapter->p2pSessionId;
365 }
366 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
367 sessionId );
368 }
369 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
370 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
371 )
372 {
373 WLANSAP_CancelRemainOnChannel(
374 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
375 }
376 else
377 {
378 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
379 __func__, pAdapter->device_mode);
380 return -EIO;
381 }
382 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
383 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
384 return 0;
385}
386
387#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
388int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
389 struct ieee80211_channel *chan, bool offchan,
390 enum nl80211_channel_type channel_type,
391 bool channel_type_valid, unsigned int wait,
392 const u8 *buf, size_t len, bool no_cck,
393 bool dont_wait_for_ack, u64 *cookie )
394#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
395int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
396 struct ieee80211_channel *chan, bool offchan,
397 enum nl80211_channel_type channel_type,
398 bool channel_type_valid, unsigned int wait,
399 const u8 *buf, size_t len, u64 *cookie )
400#else
401int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
402 struct ieee80211_channel *chan,
403 enum nl80211_channel_type channel_type,
404 bool channel_type_valid,
405 const u8 *buf, size_t len, u64 *cookie )
406#endif //LINUX_VERSION_CODE
407{
408 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
409 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
410 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
411#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
412 hdd_adapter_t *goAdapter;
413#endif
414
415 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
416 __func__,pAdapter->device_mode);
417
418 //Call sme API to send out a action frame.
419 // OR can we send it directly through data path??
420 // After tx completion send tx status back.
421 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
422 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
423 )
424 {
425 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
426 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
427 if (type == SIR_MAC_MGMT_FRAME)
428 {
429 if (subType == SIR_MAC_MGMT_PROBE_RSP)
430 {
431 /* Drop Probe response recieved from supplicant, as for GO and
432 SAP PE itself sends probe response
433 */
434 goto err_rem_channel;
435 }
436 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
437 (subType == SIR_MAC_MGMT_DEAUTH))
438 {
439 /* Deauth/Disassoc received from supplicant, If we simply
440 * transmit the frame over air, driver doesn't come to know
441 * about the deauth/disassoc. Because of this reason the
442 * supplicant and driver will be out of sync.
443 * Drop the frame here and initiate the disassoc procedure
444 * from driver, the core stack will take care of sending
445 * disassoc frame and indicating corresponding events to supplicant.
446 */
447 tANI_U8 dstMac[ETH_ALEN] = {0};
448 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
449 hddLog(VOS_TRACE_LEVEL_INFO,
450 "%s: Deauth/Disassoc received for STA:"
451 "%02x:%02x:%02x:%02x:%02x:%02x",
452 __func__,
453 dstMac[0], dstMac[1], dstMac[2],
454 dstMac[3], dstMac[4], dstMac[5]);
455 hdd_softap_sta_disassoc(pAdapter, (v_U8_t *)&dstMac);
456 goto err_rem_channel;
457 }
458 }
459 }
460
461 if( NULL != cfgState->buf )
462 return -EBUSY;
463
464 hddLog( LOG1, "Action frame tx request");
465
466#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
467 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
468
469 //If GO adapter exists and operating on same frequency
470 //then we will not request remain on channel
471 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
472 == goAdapter->sessionCtx.ap.operatingChannel ) )
473 {
474 goto send_frame;
475 }
476#endif
477
478#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
479 if( offchan && wait)
480 {
481 int status;
482
483 // In case of P2P Client mode if we are already
484 // on the same channel then send the frame directly
485
486 if((cfgState->remain_on_chan_ctx != NULL) &&
487 (cfgState->current_freq == chan->center_freq)
488 )
489 {
490 goto send_frame;
491 }
492
493 INIT_COMPLETION(pAdapter->offchannel_tx_event);
494
495 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
496 chan, channel_type, wait, cookie,
497 OFF_CHANNEL_ACTION_TX);
498
499 if(0 != status)
500 {
501 if( (-EBUSY == status) &&
502 (cfgState->current_freq == chan->center_freq) )
503 {
504 goto send_frame;
505 }
506 goto err_rem_channel;
507 }
508
509 /* Wait for driver to be ready on the requested channel */
510 status = wait_for_completion_interruptible_timeout(
511 &pAdapter->offchannel_tx_event,
512 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
513 if(!status)
514 {
515 hddLog( LOGE, "Not able to complete remain on channel request"
516 " within timeout period");
517 goto err_rem_channel;
518 }
519 }
520 else if ( offchan )
521 {
522 /* Check before sending action frame
523 whether we already remain on channel */
524 if(NULL == cfgState->remain_on_chan_ctx)
525 {
526 goto err_rem_channel;
527 }
528 }
529 send_frame:
530#endif
531
532 cfgState->buf = vos_mem_malloc( len ); //buf;
533 if( cfgState->buf == NULL )
534 return -ENOMEM;
535
536 cfgState->len = len;
537
538 vos_mem_copy( cfgState->buf, buf, len);
539
540#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
541 if( cfgState->remain_on_chan_ctx )
542 {
543 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
544 *cookie = cfgState->action_cookie;
545 }
546 else
547 {
548#endif
549 *cookie = (tANI_U32) cfgState->buf;
550 cfgState->action_cookie = *cookie;
551#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
552 }
553#endif
554
555 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
556 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)
557 )
558 {
559 tANI_U8 sessionId = pAdapter->sessionId;
560 if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
561 {
562 if ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode )
563 {
564 sessionId = pAdapter->p2pSessionId;
565 vos_mem_copy((void*) (&buf[10]),
566 (void*) (&pHddCtx->p2pDeviceAddress.bytes[0]),
567 sizeof(tSirMacAddr));
568 }
569 }
570 if (eHAL_STATUS_SUCCESS !=
571 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
572 sessionId, buf, len) )
573 {
574 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
575 "%s: sme_sendAction returned fail", __func__);
576 goto err;
577 }
578 }
579 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
580 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
581 )
582 {
583 if( eHAL_STATUS_SUCCESS !=
584 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
585 buf, len ) )
586 {
587 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
588 "%s: WLANSAP_SendAction returned fail", __func__);
589 goto err;
590 }
591 }
592
593 return 0;
594err:
595 hdd_sendActionCnf( pAdapter, FALSE );
596 return 0;
597err_rem_channel:
598 *cookie = (tANI_U32)cfgState;
599 cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL );
600 return 0;
601}
602
603#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
604int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
605 struct net_device *dev,
606 u64 cookie)
607{
608 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
609}
610#endif
611
612void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
613{
614 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
615
616 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
617 if( NULL == cfgState->buf )
618 {
619 VOS_ASSERT( cfgState->buf );
620 return;
621 }
622
623 /* If skb is NULL it means this packet was received on CFG80211 interface
624 * else it was received on Monitor interface */
625 if( cfgState->skb == NULL )
626 {
627 /*
628 * buf is the same pointer it passed us to send. Since we are sending
629 * it through control path, we use different buffers.
630 * In case of mac80211, they just push it to the skb and pass the same
631 * data while sending tx ack status.
632 * */
633 cfg80211_mgmt_tx_status( pAdapter->dev, cfgState->action_cookie,
634 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
635 vos_mem_free( cfgState->buf );
636 cfgState->buf = NULL;
637 }
638 else
639 {
640 hdd_adapter_t* pMonAdapter =
641 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
642 if( pMonAdapter == NULL )
643 {
644 hddLog( LOGE, "Not able to get Monitor Adapter");
645 cfgState->skb = NULL;
646 vos_mem_free( cfgState->buf );
647 cfgState->buf = NULL;
648 complete(&pAdapter->tx_action_cnf_event);
649 return;
650 }
651 /* Send TX completion feedback over monitor interface. */
652 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
653 cfgState->skb = NULL;
654 vos_mem_free( cfgState->buf );
655 cfgState->buf = NULL;
656 /* Look for the next Mgmt packet to TX */
657 hdd_mon_tx_mgmt_pkt(pAdapter);
658 }
659 complete(&pAdapter->tx_action_cnf_event);
660}
661
662/**
663 * hdd_setP2pNoa
664 *
665 *FUNCTION:
666 * This function is called from hdd_hostapd_ioctl function when Driver
667 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
668 *
669 *LOGIC:
670 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
671 *
672 *ASSUMPTIONS:
673 *
674 *
675 *NOTE:
676 *
677 * @param dev Pointer to net device structure
678 * @param command Pointer to command
679 *
680 * @return Status
681 */
682
683int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
684{
685 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
686 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
687 VOS_STATUS status = VOS_STATUS_SUCCESS;
688 tP2pPsConfig NoA;
689 int count, duration, interval;
690 char *param;
691
692 param = strchr(command, ' ');
693 if (param == NULL)
694 return -1;
695 param++;
696 sscanf(param, "%d %d %d", &count, &duration, &interval);
697 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
698 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
699 __func__, count, duration, interval);
700
701 /* PS Selection
702 * Periodic NoA (2)
703 * Single NOA (4)
704 */
705 NoA.opp_ps = 0;
706 NoA.ctWindow = 0;
707 if (count == 1)
708 {
709 NoA.duration = 0;
710 NoA.single_noa_duration = duration;
711 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
712 }
713 else
714 {
715 NoA.duration = duration;
716 NoA.single_noa_duration = 0;
717 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
718 }
719 NoA.interval = interval;
720 NoA.count = count;
721 NoA.sessionid = pAdapter->sessionId;
722
723 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
724 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
725 "interval %d count %d single noa duration %d "
726 "PsSelection %x \n", __func__, NoA.opp_ps,
727 NoA.ctWindow, NoA.duration, NoA.interval,
728 NoA.count, NoA.single_noa_duration,
729 NoA.psSelection);
730
731 sme_p2pSetPs(hHal, &NoA);
732 return status;
733}
734
735/**
736 * hdd_setP2pOpps
737 *
738 *FUNCTION:
739 * This function is called from hdd_hostapd_ioctl function when Driver
740 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
741 *
742 *LOGIC:
743 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
744 *
745 *ASSUMPTIONS:
746 *
747 *
748 *NOTE:
749 *
750 * @param dev Pointer to net device structure
751 * @param command Pointer to command
752 *
753 * @return Status
754 */
755
756int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
757{
758 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
759 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
760 VOS_STATUS status = VOS_STATUS_SUCCESS;
761 tP2pPsConfig NoA;
762 char *param;
763 int legacy_ps, opp_ps, ctwindow;
764
765 param = strchr(command, ' ');
766 if (param == NULL)
767 return -1;
768 param++;
769 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
770 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
771 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
772 __func__, legacy_ps, opp_ps, ctwindow);
773
774 /* PS Selection
775 * Opportunistic Power Save (1)
776 */
777
778 /* From wpa_cli user need to use separate command to set ctWindow and Opps
779 * When user want to set ctWindow during that time other parameters
780 * values are coming from wpa_supplicant as -1.
781 * Example : User want to set ctWindow with 30 then wpa_cli command :
782 * P2P_SET ctwindow 30
783 * Command Received at hdd_hostapd_ioctl is as below:
784 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
785 */
786 if (ctwindow != -1)
787 {
788
789 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
790 "Opportunistic Power Save is %s \n",
791 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
792
793 if (ctwindow != pAdapter->ctw)
794 {
795 pAdapter->ctw = ctwindow;
796
797 if(pAdapter->ops)
798 {
799 NoA.opp_ps = pAdapter->ops;
800 NoA.ctWindow = pAdapter->ctw;
801 NoA.duration = 0;
802 NoA.single_noa_duration = 0;
803 NoA.interval = 0;
804 NoA.count = 0;
805 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
806 NoA.sessionid = pAdapter->sessionId;
807
808 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
809 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
810 "interval %d count %d single noa duration %d "
811 "PsSelection %x \n", __func__, NoA.opp_ps,
812 NoA.ctWindow, NoA.duration, NoA.interval,
813 NoA.count, NoA.single_noa_duration,
814 NoA.psSelection);
815
816 sme_p2pSetPs(hHal, &NoA);
817 }
818 return 0;
819 }
820 }
821
822 if (opp_ps != -1)
823 {
824 pAdapter->ops = opp_ps;
825
826 if ((opp_ps != -1) && (pAdapter->ctw))
827 {
828 NoA.opp_ps = opp_ps;
829 NoA.ctWindow = pAdapter->ctw;
830 NoA.duration = 0;
831 NoA.single_noa_duration = 0;
832 NoA.interval = 0;
833 NoA.count = 0;
834 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
835 NoA.sessionid = pAdapter->sessionId;
836
837 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
838 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
839 "interval %d count %d single noa duration %d "
840 "PsSelection %x \n", __func__, NoA.opp_ps,
841 NoA.ctWindow, NoA.duration, NoA.interval,
842 NoA.count, NoA.single_noa_duration,
843 NoA.psSelection);
844
845 sme_p2pSetPs(hHal, &NoA);
846 }
847 }
848 return status;
849}
850
851int hdd_setP2pPs( struct net_device *dev, void *msgData )
852{
853 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
854 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
855 VOS_STATUS status = VOS_STATUS_SUCCESS;
856 tP2pPsConfig NoA;
857 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
858
859 NoA.opp_ps = pappNoA->opp_ps;
860 NoA.ctWindow = pappNoA->ctWindow;
861 NoA.duration = pappNoA->duration;
862 NoA.interval = pappNoA->interval;
863 NoA.count = pappNoA->count;
864 NoA.single_noa_duration = pappNoA->single_noa_duration;
865 NoA.psSelection = pappNoA->psSelection;
866 NoA.sessionid = pAdapter->sessionId;
867
868 sme_p2pSetPs(hHal, &NoA);
869 return status;
870}
871#endif
872
873static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
874{
875 tANI_U8 sessionType;
876
877 switch( type )
878 {
879 case NL80211_IFTYPE_AP:
880 sessionType = WLAN_HDD_SOFTAP;
881 break;
882 case NL80211_IFTYPE_P2P_GO:
883 sessionType = WLAN_HDD_P2P_GO;
884 break;
885 case NL80211_IFTYPE_P2P_CLIENT:
886 sessionType = WLAN_HDD_P2P_CLIENT;
887 break;
888 case NL80211_IFTYPE_STATION:
889 sessionType = WLAN_HDD_INFRA_STATION;
890 break;
891 case NL80211_IFTYPE_MONITOR:
892 sessionType = WLAN_HDD_MONITOR;
893 break;
894 default:
895 sessionType = WLAN_HDD_INFRA_STATION;
896 break;
897 }
898
899 return sessionType;
900}
901
902#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
903struct net_device* wlan_hdd_add_virtual_intf(
904 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
905 u32 *flags, struct vif_params *params )
906#else
907int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
908 enum nl80211_iftype type,
909 u32 *flags, struct vif_params *params )
910#endif
911{
912 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
913 hdd_adapter_t* pAdapter = NULL;
914
915 ENTER();
916
Jeff Johnson04dd8a82012-06-29 20:41:40 -0700917 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
918 {
919 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
920 "interfaces of same type are not supported currently.",__func__, type);
921 return NULL;
922 }
923
Jeff Johnson295189b2012-06-20 16:38:30 -0700924 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
925 {
926 if( (NL80211_IFTYPE_P2P_GO == type) ||
927 (NL80211_IFTYPE_P2P_CLIENT == type) )
928 {
929 /* Generate the P2P Interface Address. this address must be
930 * different from the P2P Device Address.
931 */
932 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
933 p2pDeviceAddress.bytes[4] ^= 0x80;
934 pAdapter = hdd_open_adapter( pHddCtx,
935 wlan_hdd_get_session_type(type),
936 name, p2pDeviceAddress.bytes,
937 VOS_TRUE );
938 }
939 }
940 else
941 {
942 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
943 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
944 }
945
946 if( NULL == pAdapter)
947 {
948 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
949#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
950 return NULL;
951#else
952 return -EINVAL;
953#endif
954 }
955 EXIT();
956#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
957 return pAdapter->dev;
958#else
959 return 0;
960#endif
961}
962
963int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
964{
965 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
966 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
967 ENTER();
968
969 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
970 __func__,pVirtAdapter->device_mode);
971
972 wlan_hdd_release_intf_addr( pHddCtx,
973 pVirtAdapter->macAddressCurrent.bytes );
974
975 hdd_stop_adapter( pHddCtx, pVirtAdapter );
976 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
977 EXIT();
978 return 0;
979}
980
981void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
982 tANI_U32 nFrameLength, tANI_U8* pbFrames,
983 tANI_U8 frameType )
984{
985 //Indicate a Frame over Monitor Intf.
986 int rxstat;
987 struct sk_buff *skb = NULL;
988 int needed_headroom = 0;
989 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
990 HDD_RX_FLAG_MMIC_STRIPPED;
991
992 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
993
994 VOS_ASSERT( (pbFrames != NULL) );
995
996 /* room for the radiotap header based on driver features
997 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
998 * RX flags.
999 * */
1000 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1001
1002 //alloc skb here
1003 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1004 if (unlikely(NULL == skb))
1005 {
1006 hddLog( LOGW, FL("Unable to allocate skb"));
1007 return;
1008 }
1009 skb_reserve(skb, VPKT_SIZE_BUFFER);
1010 if (unlikely(skb_headroom(skb) < nFrameLength))
1011 {
1012 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1013 "HDD [%d]: Insufficient headroom, "
1014 "head[%p], data[%p], req[%d]",
1015 __LINE__, skb->head, skb->data, nFrameLength);
1016 kfree_skb(skb);
1017 return ;
1018 }
1019 // actually push the data
1020 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1021 /* prepend radiotap information */
1022 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1023 {
1024 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1025 //free skb
1026 kfree_skb(skb);
1027 return ;
1028 }
1029
1030 skb_reset_mac_header( skb );
1031 skb->dev = pMonAdapter->dev;
1032 skb->protocol = eth_type_trans( skb, skb->dev );
1033 skb->ip_summed = CHECKSUM_UNNECESSARY;
1034 rxstat = netif_rx_ni(skb);
1035 if( NET_RX_SUCCESS == rxstat )
1036 {
1037 hddLog( LOG1, FL("Success"));
1038 }
1039 else
1040 hddLog( LOGE, FL("Failed %d"), rxstat);
1041
1042 return ;
1043}
1044
1045void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1046 tANI_U32 nFrameLength,
1047 tANI_U8* pbFrames,
1048 tANI_U8 frameType,
1049 tANI_U32 rxChan )
1050{
1051 tANI_U16 freq;
1052
1053 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1054 __func__, frameType, nFrameLength);
1055
1056 if (NULL == pAdapter)
1057 {
1058 hddLog( LOGE, FL("pAdapter is NULL"));
1059 return;
1060 }
1061
1062 if (NULL == pAdapter->dev)
1063 {
1064 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1065 return;
1066 }
1067
1068 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1069 {
1070 hddLog( LOGE, FL("pAdapter has invalid magic"));
1071 return;
1072 }
1073
1074 if( !nFrameLength )
1075 {
1076 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1077 return;
1078 }
1079
1080 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1081 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1082 )
1083 {
1084 hdd_adapter_t *pMonAdapter =
1085 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1086
1087 if( NULL != pMonAdapter )
1088 {
1089 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1090 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1091 pbFrames, frameType);
1092 return;
1093 }
1094 }
1095
1096 //Channel indicated may be wrong. TODO
1097 //Indicate an action frame.
1098 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1099 {
1100 freq = ieee80211_channel_to_frequency( rxChan,
1101 IEEE80211_BAND_2GHZ);
1102 }
1103 else
1104 {
1105 freq = ieee80211_channel_to_frequency( rxChan,
1106 IEEE80211_BAND_5GHZ);
1107 }
1108
1109 //Indicate Frame Over Normal Interface
1110 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1111
1112#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
1113 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1114 pbFrames, nFrameLength,
1115 GFP_ATOMIC );
1116#else
1117 cfg80211_rx_mgmt( pAdapter->dev, freq,
1118 pbFrames, nFrameLength,
1119 GFP_ATOMIC );
1120#endif //LINUX_VERSION_CODE
1121}
1122
1123/*
1124 * ieee80211_add_rx_radiotap_header - add radiotap header
1125 */
1126static int hdd_wlan_add_rx_radiotap_hdr (
1127 struct sk_buff *skb, int rtap_len, int flag )
1128{
1129 u8 rtap_temp[20] = {0};
1130 struct ieee80211_radiotap_header *rthdr;
1131 unsigned char *pos;
1132 u16 rx_flags = 0;
1133
1134 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1135
1136 /* radiotap header, set always present flags */
1137 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1138 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1139 rthdr->it_len = cpu_to_le16(rtap_len);
1140
1141 pos = (unsigned char *) (rthdr + 1);
1142
1143 /* the order of the following fields is important */
1144
1145 /* IEEE80211_RADIOTAP_FLAGS */
1146 *pos = 0;
1147 pos++;
1148
1149 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1150 /* ensure 2 byte alignment for the 2 byte field as required */
1151 if ((pos - (u8 *)rthdr) & 1)
1152 pos++;
1153 put_unaligned_le16(rx_flags, pos);
1154 pos += 2;
1155
1156 // actually push the data
1157 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1158
1159 return 0;
1160}
1161
1162static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1163 hdd_cfg80211_state_t* cfgState,
1164 tANI_BOOLEAN actionSendSuccess )
1165{
1166 struct ieee80211_radiotap_header *rthdr;
1167 unsigned char *pos;
1168 struct sk_buff *skb = cfgState->skb;
1169
1170 /* 2 Byte for TX flags and 1 Byte for Retry count */
1171 u32 rtHdrLen = sizeof(*rthdr) + 3;
1172
1173 u8 *data;
1174
1175 /* We have to return skb with Data starting with MAC header. We have
1176 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1177 * entire skb->len from skb and then we will push cfgState->buf to skb
1178 * */
1179 if( NULL == skb_pull(skb, skb->len) )
1180 {
1181 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1182 kfree_skb(cfgState->skb);
1183 return;
1184 }
1185
1186 data = skb_push( skb, cfgState->len );
1187
1188 if (data == NULL)
1189 {
1190 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1191 kfree_skb( cfgState->skb );
1192 return;
1193 }
1194
1195 memcpy( data, cfgState->buf, cfgState->len );
1196
1197 /* send frame to monitor interfaces now */
1198 if( skb_headroom(skb) < rtHdrLen )
1199 {
1200 hddLog( LOGE, FL("No headroom for rtap header"));
1201 kfree_skb(cfgState->skb);
1202 return;
1203 }
1204
1205 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1206
1207 memset( rthdr, 0, rtHdrLen );
1208 rthdr->it_len = cpu_to_le16( rtHdrLen );
1209 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1210 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1211 );
1212
1213 pos = (unsigned char *)( rthdr+1 );
1214
1215 // Fill TX flags
1216 *pos = actionSendSuccess;
1217 pos += 2;
1218
1219 // Fill retry count
1220 *pos = 0;
1221 pos++;
1222
1223 skb_set_mac_header( skb, 0 );
1224 skb->ip_summed = CHECKSUM_UNNECESSARY;
1225 skb->pkt_type = PACKET_OTHERHOST;
1226 skb->protocol = htons(ETH_P_802_2);
1227 memset( skb->cb, 0, sizeof( skb->cb ) );
1228 if (in_interrupt())
1229 netif_rx( skb );
1230 else
1231 netif_rx_ni( skb );
1232
1233 /* Enable Queues which we have disabled earlier */
1234 netif_tx_start_all_queues( pAdapter->dev );
1235
1236}
1237#endif // CONFIG_CFG80211