blob: ae92a9baed3c45efca44dac61d9db632b0420af2 [file] [log] [blame]
/*
* Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*===========================================================================
L I M _ P 2 P . C
OVERVIEW:
This software unit holds the implementation of the WLAN Protocol Engine for
P2P.
Copyright (c) 2011 QUALCOMM Incorporated.
All Rights Reserved.
Qualcomm Confidential and Proprietary
===========================================================================*/
/*===========================================================================
EDIT HISTORY FOR FILE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header$$DateTime$$Author$
when who what, where, why
---------- --- --------------------------------------------------------
2011-05-02 djindal Corrected file indentation and changed remain on channel
handling for concurrency.
===========================================================================*/
#include "limUtils.h"
#include "limSessionUtils.h"
#include "wlan_qct_wda.h"
#define PROBE_RSP_IE_OFFSET 36
#define BSSID_OFFSET 16
#define ADDR2_OFFSET 10
#define ACTION_OFFSET 24
/* A DFS channel can be ACTIVE for max 9000 msec, from the last
received Beacon/Prpbe Resp. */
#define MAX_TIME_TO_BE_ACTIVE_CHANNEL 9000
#define REMAIN_ON_CHANNEL_UNKNOWN_ACTION_CATEGORY 0x20
#define VENDOR_SPECIFIC_ELEMENT_ID 221
#define REMAIN_ON_CHANNEL_MSG_SIZE 55
#define REMAIN_ON_CHANNEL_FIRST_MARKER_FRAME 1
#define REMAIN_ON_CHANNEL_SECOND_MARKER_FRAME 2
void limRemainOnChnlSuspendLinkHdlr(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data);
void limRemainOnChnlSetLinkStat(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data, tpPESession psessionEntry);
void limExitRemainOnChannel(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data, tpPESession psessionEntry);
void limRemainOnChnRsp(tpAniSirGlobal pMac, eHalStatus status, tANI_U32 *data);
extern tSirRetStatus limSetLinkState(
tpAniSirGlobal pMac, tSirLinkState state,
tSirMacAddr bssId, tSirMacAddr selfMacAddr,
tpSetLinkStateCallback callback, void *callbackArg);
static tSirRetStatus limCreateSessionForRemainOnChn(tpAniSirGlobal pMac, tPESession **ppP2pSession);
eHalStatus limP2PActionCnf(tpAniSirGlobal pMac, tANI_U32 txCompleteSuccess);
/*----------------------------------------------------------------------------
*
* The function limSendRemainOnChannelDebugMarkerFrame, prepares Marker frame
* for Start and End of remain on channel with RemainOnChannelMsg as Vendor
* Specific information element of the frame.
*
*----------------------------------------------------------------------------*/
tSirRetStatus limSendRemainOnChannelDebugMarkerFrame(tpAniSirGlobal pMac,
tANI_U8 *remainOnChannelMsg)
{
tSirMacAddr magicMacAddr= {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
tANI_U32 nBytes, nPayload;
tSirRetStatus nSirStatus;
tANI_U8 *pFrame;
void *pPacket;
eHalStatus halstatus;
tANI_U8 txFlag = 0;
publicVendorSpecific *pPublicVendorSpecific;
pPublicVendorSpecific = vos_mem_malloc(sizeof(publicVendorSpecific));
if( pPublicVendorSpecific == NULL )
{
limLog( pMac, LOGE,
FL( "Unable to allocate memory for Vendor specific information"
" element" ) );
return eSIR_MEM_ALLOC_FAILED;
}
// Assigning Action category code as unknown as this is debug marker frame
pPublicVendorSpecific->category = REMAIN_ON_CHANNEL_UNKNOWN_ACTION_CATEGORY;
pPublicVendorSpecific->elementid = VENDOR_SPECIFIC_ELEMENT_ID;
pPublicVendorSpecific->length = strlen(remainOnChannelMsg);
nPayload = sizeof(publicVendorSpecific) + pPublicVendorSpecific->length;
nBytes = nPayload + sizeof( tSirMacMgmtHdr );
halstatus = palPktAlloc( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( tANI_U16 )nBytes, ( void** ) &pFrame,
( void** ) &pPacket );
if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
{
limLog( pMac, LOGE, FL("Failed to allocate %d bytes for a Remain"
" on channel action frame."), nBytes );
nSirStatus = eSIR_MEM_ALLOC_FAILED;
goto end;
}
vos_mem_zero( pFrame, nBytes );
// Populate frame with MAC header
nSirStatus = limPopulateMacHeader( pMac, pFrame, SIR_MAC_MGMT_FRAME,
SIR_MAC_MGMT_ACTION, magicMacAddr,
pMac->lim.gSelfMacAddr);
if ( eSIR_SUCCESS != nSirStatus )
{
limLog( pMac, LOGE, FL("Failed to populate the buffer descriptor for a"
" Action frame for remain on channel.") );
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pFrame, ( void* ) pPacket );
goto end;
}
// Copy Public Vendor specific fields to frame's information element
vos_mem_copy( (pFrame + (sizeof( tSirMacMgmtHdr ))),
pPublicVendorSpecific, sizeof(publicVendorSpecific) );
// Copy Remain On channel message to Vendor Specific information field
vos_mem_copy( (pFrame + (nBytes - pPublicVendorSpecific->length)),
remainOnChannelMsg, pPublicVendorSpecific->length );
halstatus = halTxFrame( pMac, pPacket,
( tANI_U16 ) sizeof(tSirMacMgmtHdr) + nPayload,
HAL_TXRX_FRM_802_11_MGMT,
ANI_TXDIR_TODS,
7,//SMAC_SWBD_TX_TID_MGMT_HIGH,
limTxComplete, pFrame, txFlag );
if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
{
limLog( pMac, LOGE, FL("could not send marker frame for"
" remain on channel!" ));
//Pkt will be freed up by the callback
nSirStatus = eSIR_FAILURE;
goto end;
}
nSirStatus = eSIR_SUCCESS;
end:
vos_mem_free( pPublicVendorSpecific );
return nSirStatus;
}
/*-------------------------------------------------------------------------
*
* This function forms message for start of remain on channel with channel
* number, duration and sequence number. This message is added as data of
* vendor specific information element of Debug Marker Frame. Message will
* be in form "START-REMAIN-ON-CHANNEL<first/second-frame>-CHN=<channel>"
* "-FOR-DUR=<duraion>-SEQ=<sequence-num>"
*
*-------------------------------------------------------------------------*/
eHalStatus limPrepareAndSendStartRemainOnChannelMsg(tpAniSirGlobal pMac,
tSirRemainOnChnReq *MsgRemainonChannel, tANI_U8 id)
{
tANI_U8 *startRemainOnChannelMsg;
eHalStatus status = eHAL_STATUS_SUCCESS;
startRemainOnChannelMsg = vos_mem_malloc( REMAIN_ON_CHANNEL_MSG_SIZE );
if( NULL == startRemainOnChannelMsg )
{
limLog(pMac, LOGE,
FL("Unable to allocate memory for remain on channel message"));
return eHAL_STATUS_FAILURE;
}
snprintf(startRemainOnChannelMsg, REMAIN_ON_CHANNEL_MSG_SIZE,
"START-REMAIN-ON-CHANNEL%d-CHN=%d-FOR-DUR=%d-SEQ=%d",
id, MsgRemainonChannel->chnNum, MsgRemainonChannel->duration,
pMac->lim.remOnChnSeqNum);
if( eSIR_FAILURE == limSendRemainOnChannelDebugMarkerFrame(pMac,
startRemainOnChannelMsg) )
{
limLog( pMac, LOGE,
"%s: Could not send %d debug marker frame at start"
" of remain on channel", __func__, id);
status = eHAL_STATUS_FAILURE;
}
vos_mem_free( startRemainOnChannelMsg );
return status;
}
/*----------------------------------------------------------------------------
*
* This function forms message for cancel of remain on channel. This message
* is added as data of Vendor Specific information element of debug marker
* frame.Message will be in form "CANCEL-REMAIN-ON-CHANNEL<first/second-frame>"
* "-SEQ=<sequence-num>"
*
*----------------------------------------------------------------------------*/
eHalStatus limPrepareAndSendCancelRemainOnChannelMsg(tpAniSirGlobal pMac,
tANI_U8 id)
{
tANI_U8 *cancelRemainOnChannelMsg;
eHalStatus status = eHAL_STATUS_SUCCESS;
cancelRemainOnChannelMsg = vos_mem_malloc( REMAIN_ON_CHANNEL_MSG_SIZE );
if( NULL == cancelRemainOnChannelMsg )
{
limLog( pMac, LOGE,
FL( "Unable to allocate memory for end of"
" remain on channel message" ));
return eHAL_STATUS_FAILURE;
}
snprintf(cancelRemainOnChannelMsg, REMAIN_ON_CHANNEL_MSG_SIZE,
"CANCEL-REMAIN-ON-CHANNEL%d-SEQ=%d",
id, pMac->lim.remOnChnSeqNum);
if( eSIR_FAILURE == limSendRemainOnChannelDebugMarkerFrame(pMac,
cancelRemainOnChannelMsg) )
{
limLog( pMac, LOGE,
"%s: Could not send %d marker frame to debug cancel"
" remain on channel", __func__, id);
status = eHAL_STATUS_FAILURE;
}
vos_mem_free( cancelRemainOnChannelMsg );
return status;
}
/*------------------------------------------------------------------
*
* Below function is callback function, it is called when
* WDA_SET_LINK_STATE_RSP is received from WDI. callback function for
* P2P of limSetLinkState
*
*------------------------------------------------------------------*/
void limSetLinkStateP2PCallback(tpAniSirGlobal pMac, void *callbackArg)
{
tSirRemainOnChnReq *MsgRemainonChannel = pMac->lim.gpLimRemainOnChanReq;
//Send Ready on channel indication to SME
if(pMac->lim.gpLimRemainOnChanReq)
{
limSendSmeRsp(pMac, eWNI_SME_REMAIN_ON_CHN_RDY_IND, eHAL_STATUS_SUCCESS,
pMac->lim.gpLimRemainOnChanReq->sessionId, 0);
if(pMac->lim.gDebugP2pRemainOnChannel)
{
if( eHAL_STATUS_SUCCESS == limPrepareAndSendStartRemainOnChannelMsg(
pMac,
MsgRemainonChannel,
REMAIN_ON_CHANNEL_SECOND_MARKER_FRAME) )
{
limLog( pMac, LOGE,
"%s: Successfully sent 2nd Marker frame "
"seq num = %d on start ROC", __func__,
pMac->lim.remOnChnSeqNum);
}
}
}
else
{
//This is possible in case remain on channel is aborted
limLog( pMac, LOGE, FL(" NULL pointer of gpLimRemainOnChanReq") );
}
}
/*------------------------------------------------------------------
*
* Remain on channel req handler. Initiate the INIT_SCAN, CHN_CHANGE
* and SET_LINK Request from SME, chnNum and duration to remain on channel.
*
*------------------------------------------------------------------*/
int limProcessRemainOnChnlReq(tpAniSirGlobal pMac, tANI_U32 *pMsg)
{
/* CONC_OPER_AND_LISTEN_CHNL_SAME_OPTIMIZE - Currently removed the special optimization when a concurrent session
* exists with operating channel same as P2P listen channel since it was causing issues in P2P search. The reason was
* STA-AP link entering BMPS when returning to home channel causing P2P search to miss Probe Reqs and hence not
* respond with Probe Rsp causing peer device to NOT find us.
* If we need this optimization, we need to find a way to keep the STA-AP link awake (no BMPS) on home channel when in listen state
*/
#ifdef CONC_OPER_AND_LISTEN_CHNL_SAME_OPTIMIZE
tANI_U8 i;
tpPESession psessionEntry;
#endif
#ifdef WLAN_FEATURE_P2P_INTERNAL
tpPESession pP2pSession;
#endif
tSirRemainOnChnReq *MsgBuff = (tSirRemainOnChnReq *)pMsg;
pMac->lim.gpLimRemainOnChanReq = MsgBuff;
#ifdef CONC_OPER_AND_LISTEN_CHNL_SAME_OPTIMIZE
for (i =0; i < pMac->lim.maxBssId;i++)
{
psessionEntry = peFindSessionBySessionId(pMac,i);
if ( (psessionEntry != NULL) )
{
if (psessionEntry->currentOperChannel == MsgBuff->chnNum)
{
tANI_U32 val;
tSirMacAddr nullBssid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
pMac->lim.p2pRemOnChanTimeStamp = vos_timer_get_system_time();
pMac->lim.gTotalScanDuration = MsgBuff->duration;
/* get the duration from the request */
val = SYS_MS_TO_TICKS(MsgBuff->duration);
limLog( pMac, LOG2, "Start listen duration = %d", val);
if (tx_timer_change(
&pMac->lim.limTimers.gLimRemainOnChannelTimer, val, 0)
!= TX_SUCCESS)
{
limLog(pMac, LOGP,
FL("Unable to change remain on channel Timer val"));
goto error;
}
else if(TX_SUCCESS != tx_timer_activate(
&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
limLog(pMac, LOGP,
FL("Unable to activate remain on channel Timer"));
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
goto error;
}
#ifdef WLAN_FEATURE_P2P_INTERNAL
//Session is needed to send probe rsp
if(eSIR_SUCCESS != limCreateSessionForRemainOnChn(pMac, &pP2pSession))
{
limLog( pMac, LOGE, "Unable to create session");
goto error;
}
#endif
if ((limSetLinkState(pMac, MsgBuff->isProbeRequestAllowed?
eSIR_LINK_LISTEN_STATE:eSIR_LINK_SEND_ACTION_STATE,
nullBssid, pMac->lim.gSelfMacAddr,
limSetLinkStateP2PCallback, NULL)) != eSIR_SUCCESS)
{
limLog( pMac, LOGE, "Unable to change link state");
goto error;
}
return FALSE;
}
}
}
#endif
pMac->lim.gLimPrevMlmState = pMac->lim.gLimMlmState;
pMac->lim.gLimMlmState = eLIM_MLM_P2P_LISTEN_STATE;
pMac->lim.gTotalScanDuration = MsgBuff->duration;
/* 1st we need to suspend link with callback to initiate change channel */
limSuspendLink(pMac, eSIR_CHECK_LINK_TRAFFIC_BEFORE_SCAN,
limRemainOnChnlSuspendLinkHdlr, NULL);
return FALSE;
#ifdef CONC_OPER_AND_LISTEN_CHNL_SAME_OPTIMIZE
error:
limRemainOnChnRsp(pMac,eHAL_STATUS_FAILURE, NULL);
/* pMsg is freed by the caller */
return FALSE;
#endif
}
tSirRetStatus limCreateSessionForRemainOnChn(tpAniSirGlobal pMac, tPESession **ppP2pSession)
{
tSirRetStatus nSirStatus = eSIR_FAILURE;
tpPESession psessionEntry;
tANI_U8 sessionId;
tANI_U32 val;
if(pMac->lim.gpLimRemainOnChanReq && ppP2pSession)
{
if((psessionEntry = peCreateSession(pMac,
pMac->lim.gpLimRemainOnChanReq->selfMacAddr, &sessionId, 1)) == NULL)
{
limLog(pMac, LOGE, FL("Session Can not be created "));
/* send remain on chn failure */
return nSirStatus;
}
/* Store PE sessionId in session Table */
psessionEntry->peSessionId = sessionId;
psessionEntry->limSystemRole = eLIM_P2P_DEVICE_ROLE;
CFG_GET_STR( nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A,
psessionEntry->rateSet.rate, val , SIR_MAC_MAX_NUMBER_OF_RATES );
psessionEntry->rateSet.numRates = val;
CFG_GET_STR( nSirStatus, pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
psessionEntry->extRateSet.rate, val,
WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN );
psessionEntry->extRateSet.numRates = val;
sirCopyMacAddr(psessionEntry->selfMacAddr,
pMac->lim.gpLimRemainOnChanReq->selfMacAddr);
psessionEntry->currentOperChannel = pMac->lim.gpLimRemainOnChanReq->chnNum;
nSirStatus = eSIR_SUCCESS;
*ppP2pSession = psessionEntry;
}
return nSirStatus;
}
/*------------------------------------------------------------------
*
* limSuspenLink callback, on success link suspend, trigger change chn
*
*
*------------------------------------------------------------------*/
tSirRetStatus limRemainOnChnlChangeChnReq(tpAniSirGlobal pMac,
eHalStatus status, tANI_U32 *data)
{
tpPESession psessionEntry;
tANI_U8 sessionId = 0;
tSirRetStatus nSirStatus = eSIR_FAILURE;
if( NULL == pMac->lim.gpLimRemainOnChanReq )
{
//RemainOnChannel may have aborted
PELOGE(limLog( pMac, LOGE, FL(" gpLimRemainOnChanReq is NULL") );)
return nSirStatus;
}
/* The link is not suspended */
if (status != eHAL_STATUS_SUCCESS)
{
PELOGE(limLog( pMac, LOGE, FL(" Suspend link Failure ") );)
goto error;
}
if((psessionEntry = peFindSessionByBssid(
pMac,pMac->lim.gpLimRemainOnChanReq->selfMacAddr, &sessionId)) != NULL)
{
goto change_channel;
}
else /* Session Entry does not exist for given BSSId */
{
/* Try to Create a new session */
if(eSIR_SUCCESS != limCreateSessionForRemainOnChn(pMac, &psessionEntry))
{
limLog(pMac, LOGE, FL("Session Can not be created "));
/* send remain on chn failure */
goto error;
}
}
change_channel:
/* change channel to the requested by RemainOn Chn*/
limChangeChannelWithCallback(pMac,
pMac->lim.gpLimRemainOnChanReq->chnNum,
limRemainOnChnlSetLinkStat, NULL, psessionEntry);
return eSIR_SUCCESS;
error:
limRemainOnChnRsp(pMac,eHAL_STATUS_FAILURE, NULL);
return eSIR_FAILURE;
}
void limRemainOnChnlSuspendLinkHdlr(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data)
{
limRemainOnChnlChangeChnReq(pMac, status, data);
return;
}
/*------------------------------------------------------------------
*
* Set the LINK state to LISTEN to allow only PROBE_REQ and Action frames
*
*------------------------------------------------------------------*/
void limRemainOnChnlSetLinkStat(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data, tpPESession psessionEntry)
{
tANI_U32 val;
tSirRemainOnChnReq *MsgRemainonChannel = pMac->lim.gpLimRemainOnChanReq;
tSirMacAddr nullBssid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (status != eHAL_STATUS_SUCCESS)
{
limLog( pMac, LOGE, FL("Change channel not successful"));
goto error1;
}
// Start timer here to come back to operating channel.
pMac->lim.limTimers.gLimRemainOnChannelTimer.sessionId =
psessionEntry->peSessionId;
pMac->lim.p2pRemOnChanTimeStamp = vos_timer_get_system_time();
pMac->lim.gTotalScanDuration = MsgRemainonChannel->duration;
/* get the duration from the request */
val = SYS_MS_TO_TICKS(MsgRemainonChannel->duration);
limLog( pMac, LOG2, "Start listen duration = %d", val);
if (tx_timer_change(&pMac->lim.limTimers.gLimRemainOnChannelTimer,
val, 0) != TX_SUCCESS)
{
/**
* Could not change Remain on channel Timer. Log error.
*/
limLog(pMac, LOGP,
FL("Unable to change remain on channel Timer val"));
goto error;
}
if(TX_SUCCESS !=
tx_timer_activate(&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
limLog( pMac, LOGE,
"%s: remain on channel Timer Start Failed", __func__);
goto error;
}
if (pMac->lim.gDebugP2pRemainOnChannel)
{
pMac->lim.remOnChnSeqNum++;
if( eHAL_STATUS_SUCCESS == limPrepareAndSendStartRemainOnChannelMsg(
pMac, MsgRemainonChannel,
REMAIN_ON_CHANNEL_FIRST_MARKER_FRAME) )
{
limLog( pMac, LOGE,
"%s: Successfully sent 1st marker frame with seq num = %d"
" on start ROC", __func__, pMac->lim.remOnChnSeqNum);
}
}
if ((limSetLinkState(pMac, MsgRemainonChannel->isProbeRequestAllowed?
eSIR_LINK_LISTEN_STATE:eSIR_LINK_SEND_ACTION_STATE,nullBssid,
pMac->lim.gSelfMacAddr, limSetLinkStateP2PCallback,
NULL)) != eSIR_SUCCESS)
{
limLog( pMac, LOGE, "Unable to change link state");
goto error;
}
return;
error:
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
error1:
limRemainOnChnRsp(pMac,eHAL_STATUS_FAILURE, NULL);
return;
}
/*------------------------------------------------------------------
*
* lim Insert NOA timer timeout callback - when timer fires, deactivate it and send
* scan rsp to csr/hdd
*
*------------------------------------------------------------------*/
void limProcessInsertSingleShotNOATimeout(tpAniSirGlobal pMac)
{
/* timeout means start NOA did not arrive; we need to deactivate and change the timer for
* future activations
*/
limDeactivateAndChangeTimer(pMac, eLIM_INSERT_SINGLESHOT_NOA_TIMER);
/* Even if insert NOA timedout, go ahead and process/send stored SME request */
limProcessRegdDefdSmeReqAfterNOAStart(pMac);
return;
}
/*-----------------------------------------------------------------
* lim Insert Timer callback function to check active DFS channels
* and convert them to passive channels if there was no
* beacon/proberesp for MAX_TIME_TO_BE_ACTIVE_CHANNEL time
*------------------------------------------------------------------*/
void limConvertActiveChannelToPassiveChannel(tpAniSirGlobal pMac )
{
tANI_U32 currentTime;
tANI_U32 lastTime = 0;
tANI_U32 timeDiff;
tANI_U8 i;
currentTime = vos_timer_get_system_time();
for (i = 1; i < SIR_MAX_24G_5G_CHANNEL_RANGE ; i++)
{
if ((pMac->lim.dfschannelList.timeStamp[i]) != 0)
{
lastTime = pMac->lim.dfschannelList.timeStamp[i];
if (currentTime >= lastTime)
{
timeDiff = (currentTime - lastTime);
}
else
{
timeDiff = (0xFFFFFFFF - lastTime) + currentTime;
}
if (timeDiff >= MAX_TIME_TO_BE_ACTIVE_CHANNEL)
{
limCovertChannelScanType( pMac, i,FALSE);
pMac->lim.dfschannelList.timeStamp[i] = 0;
}
}
}
/* lastTime is zero if there is no DFS active channels in the list.
* If this is non zero then we have active DFS channels so restart the timer.
*/
if (lastTime != 0)
{
if (tx_timer_activate(
&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer)
!= TX_SUCCESS)
{
limLog(pMac, LOGE, FL("Could not activate Active to Passive Channel timer"));
}
}
return;
}
/*------------------------------------------------------------------
*
* limSetLinkState callback function.
*
*------------------------------------------------------------------*/
void limSetlinkStateCallback(tpAniSirGlobal pMac, void *callbackArg)
{
if(pMac->lim.gDebugP2pRemainOnChannel)
{
if (eHAL_STATUS_SUCCESS == limPrepareAndSendCancelRemainOnChannelMsg(
pMac,
REMAIN_ON_CHANNEL_SECOND_MARKER_FRAME))
{
limLog( pMac, LOGE,
"%s: Successfully sent 2nd marker frame with seq num=%d"
" on cancel ROC", __func__, pMac->lim.remOnChnSeqNum);
}
}
return;
}
/*------------------------------------------------------------------
*
* limchannelchange callback, on success channel change, set the
* link_state to LISTEN
*
*------------------------------------------------------------------*/
void limProcessRemainOnChnTimeout(tpAniSirGlobal pMac)
{
tpPESession psessionEntry;
tSirMacAddr nullBssid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//Timer might get extended while Sending Action Frame
//In that case don't process Channel Timeout
if (tx_timer_running(&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
limLog( pMac, LOGE,
"still timer is running already and not processing limProcessRemainOnChnTimeout");
return;
}
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
if (NULL == pMac->lim.gpLimRemainOnChanReq)
{
limLog( pMac, LOGE, "No Remain on channel pending");
return;
}
if(pMac->lim.gDebugP2pRemainOnChannel)
{
if (eHAL_STATUS_SUCCESS == limPrepareAndSendCancelRemainOnChannelMsg(
pMac,
REMAIN_ON_CHANNEL_FIRST_MARKER_FRAME))
{
limLog( pMac, LOGE,
"%s: Successfully sent 1st marker frame with seqnum = %d"
" on cancel ROC", __func__, pMac->lim.remOnChnSeqNum);
}
}
/* get the previous valid LINK state */
if (limSetLinkState(pMac, eSIR_LINK_IDLE_STATE, nullBssid,
pMac->lim.gSelfMacAddr, limSetlinkStateCallback, NULL) != eSIR_SUCCESS)
{
limLog( pMac, LOGE, "Unable to change link state");
return;
}
if (pMac->lim.gLimMlmState != eLIM_MLM_P2P_LISTEN_STATE )
{
limRemainOnChnRsp(pMac,eHAL_STATUS_SUCCESS, NULL);
}
else
{
/* get the session */
if((psessionEntry = peFindSessionBySessionId(pMac,
pMac->lim.limTimers.gLimRemainOnChannelTimer.sessionId))== NULL)
{
limLog(pMac, LOGE,
FL("Session Does not exist for given sessionID"));
goto error;
}
limExitRemainOnChannel(pMac, eHAL_STATUS_SUCCESS, NULL, psessionEntry);
return;
error:
limRemainOnChnRsp(pMac,eHAL_STATUS_FAILURE, NULL);
}
return;
}
/*------------------------------------------------------------------
*
* limchannelchange callback, on success channel change, set the link_state
* to LISTEN
*
*------------------------------------------------------------------*/
void limExitRemainOnChannel(tpAniSirGlobal pMac, eHalStatus status,
tANI_U32 *data, tpPESession psessionEntry)
{
if (status != eHAL_STATUS_SUCCESS)
{
PELOGE(limLog( pMac, LOGE, "Remain on Channel Failed");)
goto error;
}
//Set the resume channel to Any valid channel (invalid).
//This will instruct HAL to set it to any previous valid channel.
peSetResumeChannel(pMac, 0, 0);
limResumeLink(pMac, limRemainOnChnRsp, NULL);
return;
error:
limRemainOnChnRsp(pMac,eHAL_STATUS_FAILURE, NULL);
return;
}
/*------------------------------------------------------------------
*
* Send remain on channel respone: Success/ Failure
*
*------------------------------------------------------------------*/
void limRemainOnChnRsp(tpAniSirGlobal pMac, eHalStatus status, tANI_U32 *data)
{
tpPESession psessionEntry;
tANI_U8 sessionId;
tSirRemainOnChnReq *MsgRemainonChannel = pMac->lim.gpLimRemainOnChanReq;
tSirMacAddr nullBssid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if ( NULL == MsgRemainonChannel )
{
PELOGE(limLog( pMac, LOGP,
"%s: No Pointer for Remain on Channel Req", __func__);)
return;
}
limLog( pMac, LOG1, "Remain on channel rsp with status %d", status);
//Incase of the Remain on Channel Failure Case
//Cleanup Everything
if(eHAL_STATUS_FAILURE == status)
{
//Deactivate Remain on Channel Timer
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
//Set the Link State to Idle
/* get the previous valid LINK state */
if (limSetLinkState(pMac, eSIR_LINK_IDLE_STATE, nullBssid,
pMac->lim.gSelfMacAddr, NULL, NULL) != eSIR_SUCCESS)
{
limLog( pMac, LOGE, "Unable to change link state");
}
pMac->lim.gLimSystemInScanLearnMode = 0;
pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE;
}
/* delete the session */
if((psessionEntry = peFindSessionByBssid(pMac,
MsgRemainonChannel->selfMacAddr,&sessionId)) != NULL)
{
if ( eLIM_P2P_DEVICE_ROLE == psessionEntry->limSystemRole )
{
peDeleteSession( pMac, psessionEntry);
}
}
/* Post the meessage to Sme */
limSendSmeRsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, status,
MsgRemainonChannel->sessionId, 0);
vos_mem_free(pMac->lim.gpLimRemainOnChanReq);
pMac->lim.gpLimRemainOnChanReq = NULL;
pMac->lim.gLimMlmState = pMac->lim.gLimPrevMlmState;
/* If remain on channel timer expired and action frame is pending then
* indicaiton confirmation with status failure */
if (pMac->lim.mgmtFrameSessionId != 0xff)
{
limLog(pMac, LOGE,
FL("Remain on channel expired, Action frame status failure"));
limP2PActionCnf(pMac, 0);
}
return;
}
/*------------------------------------------------------------------
*
* Indicate the Mgmt Frame received to SME to HDD callback
* handle Probe_req/Action frame currently
*
*------------------------------------------------------------------*/
void limSendSmeMgmtFrameInd(
tpAniSirGlobal pMac, tANI_U8 frameType,
tANI_U8 *frame, tANI_U32 frameLen, tANI_U16 sessionId,
tANI_U32 rxChannel, tpPESession psessionEntry,
tANI_S8 rxRssi)
{
tSirMsgQ mmhMsg;
tpSirSmeMgmtFrameInd pSirSmeMgmtFrame = NULL;
tANI_U16 length;
length = sizeof(tSirSmeMgmtFrameInd) + frameLen;
pSirSmeMgmtFrame = vos_mem_malloc(length);
if (NULL == pSirSmeMgmtFrame)
{
limLog(pMac, LOGP,
FL("AllocateMemory failed for eWNI_SME_LISTEN_RSP"));
return;
}
vos_mem_set((void*)pSirSmeMgmtFrame, length, 0);
pSirSmeMgmtFrame->mesgType = eWNI_SME_MGMT_FRM_IND;
pSirSmeMgmtFrame->mesgLen = length;
pSirSmeMgmtFrame->sessionId = sessionId;
pSirSmeMgmtFrame->frameType = frameType;
pSirSmeMgmtFrame->rxRssi = rxRssi;
/*
* Work around to address LIM sending wrong channel to HDD for p2p action
* frames(In case of auto GO) recieved on 5GHz channel.
* As RXP has only 4bits to store the channel, we need some mechanism to
* to distinguish between 2.4Ghz/5GHz channel. if gLimRemainOnChannelTImer
* is not running and if we get a frame then pass the Go session
* operating channel to HDD. Some vendors create separate p2p interface
* after group formation. In that case LIM session entry will be NULL for
* p2p device address. So search for p2p go session and pass it's
* operating channel.
* Need to revisit this path in case of GO+CLIENT concurrency.
*/
if( VOS_FALSE ==
tx_timer_running(&pMac->lim.limTimers.gLimRemainOnChannelTimer) )
{
tpPESession pTempSessionEntry = psessionEntry;
if( ( (NULL != pTempSessionEntry) ||
(pTempSessionEntry = limIsApSessionActive(pMac)) ) &&
(SIR_BAND_5_GHZ == limGetRFBand(pTempSessionEntry->currentOperChannel)) )
{
rxChannel = pTempSessionEntry->currentOperChannel;
}
}
pSirSmeMgmtFrame->rxChan = rxChannel;
vos_mem_zero(pSirSmeMgmtFrame->frameBuf, frameLen);
vos_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen);
mmhMsg.type = eWNI_SME_MGMT_FRM_IND;
mmhMsg.bodyptr = pSirSmeMgmtFrame;
mmhMsg.bodyval = 0;
if(VOS_TRUE == tx_timer_running(&pMac->lim.limTimers.gLimRemainOnChannelTimer) &&
( (psessionEntry != NULL) && (psessionEntry->pePersona != VOS_P2P_GO_MODE)) &&
(frameType == SIR_MAC_MGMT_ACTION))
{
unsigned int chanWaitTime, vStatus ;
limLog( pMac, LOG1, FL("Rx: Extend the gLimRemainOnChannelTimer = %d "),
pMac->lim.gTotalScanDuration);
pMac->lim.p2pRemOnChanTimeStamp = vos_timer_get_system_time();
chanWaitTime = SYS_MS_TO_TICKS(pMac->lim.gTotalScanDuration);
vStatus = tx_timer_deactivate(&pMac->lim.limTimers.gLimRemainOnChannelTimer);
if (VOS_STATUS_SUCCESS != vStatus)
{
limLog( pMac, LOGE, FL("Rx: Extend the gLimRemainOnChannelTimer"));
}
if (tx_timer_change(&pMac->lim.limTimers.gLimRemainOnChannelTimer, chanWaitTime, 0) != TX_SUCCESS)
{
limLog( pMac, LOGE, FL("Unable to change the gLimRemainOnChannelTimer"));
}
if (tx_timer_activate(&pMac->lim.limTimers.gLimRemainOnChannelTimer) != 0)
{
limLog( pMac, LOGE, FL("Unable to active the gLimRemainOnChannelTimer"));
}
}
else
{
if(frameType == SIR_MAC_MGMT_ACTION)
limLog( pMac, LOGE, FL("Rx: NO REMAIN ON CHANNEL and recd action frame "));
}
limSysProcessMmhMsgApi(pMac, &mmhMsg, ePROT);
return;
} /*** end limSendSmeListenRsp() ***/
eHalStatus limP2PActionCnf(tpAniSirGlobal pMac, tANI_U32 txCompleteSuccess)
{
limLog(pMac, LOG1,
FL(" %s txCompleteSuccess %d, Session Id %d"),
__func__, txCompleteSuccess, pMac->lim.mgmtFrameSessionId);
if (pMac->lim.mgmtFrameSessionId != 0xff)
{
/* The session entry might be invalid(0xff) action confirmation received after
* remain on channel timer expired */
limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF,
(txCompleteSuccess ? eSIR_SME_SUCCESS : eSIR_SME_SEND_ACTION_FAIL),
pMac->lim.mgmtFrameSessionId, 0);
pMac->lim.mgmtFrameSessionId = 0xff;
}
return eHAL_STATUS_SUCCESS;
}
void limSetHtCaps(tpAniSirGlobal pMac, tpPESession psessionEntry, tANI_U8 *pIeStartPtr,tANI_U32 nBytes)
{
v_U8_t *pIe=NULL;
tDot11fIEHTCaps dot11HtCap;
PopulateDot11fHTCaps(pMac, psessionEntry, &dot11HtCap);
pIe = limGetIEPtr(pMac,pIeStartPtr, nBytes,
DOT11F_EID_HTCAPS,ONE_BYTE);
limLog( pMac, LOG2, FL("pIe %p dot11HtCap.supportedMCSSet[0]=0x%x"),
pIe, dot11HtCap.supportedMCSSet[0]);
if(pIe)
{
tHtCaps *pHtcap = (tHtCaps *)&pIe[2]; //convert from unpacked to packed structure
pHtcap->advCodingCap = dot11HtCap.advCodingCap;
pHtcap->supportedChannelWidthSet = dot11HtCap.supportedChannelWidthSet;
pHtcap->mimoPowerSave = dot11HtCap.mimoPowerSave;
pHtcap->greenField = dot11HtCap.greenField;
pHtcap->shortGI20MHz = dot11HtCap.shortGI20MHz;
pHtcap->shortGI40MHz = dot11HtCap.shortGI40MHz;
pHtcap->txSTBC = dot11HtCap.txSTBC;
pHtcap->rxSTBC = dot11HtCap.rxSTBC;
pHtcap->delayedBA = dot11HtCap.delayedBA ;
pHtcap->maximalAMSDUsize = dot11HtCap.maximalAMSDUsize;
pHtcap->dsssCckMode40MHz = dot11HtCap.dsssCckMode40MHz;
pHtcap->psmp = dot11HtCap.psmp;
pHtcap->stbcControlFrame = dot11HtCap.stbcControlFrame;
pHtcap->lsigTXOPProtection = dot11HtCap.lsigTXOPProtection;
pHtcap->maxRxAMPDUFactor = dot11HtCap.maxRxAMPDUFactor;
pHtcap->mpduDensity = dot11HtCap.mpduDensity;
vos_mem_copy((void *)pHtcap->supportedMCSSet,
(void *)(dot11HtCap.supportedMCSSet),
sizeof(pHtcap->supportedMCSSet));
pHtcap->pco = dot11HtCap.pco;
pHtcap->transitionTime = dot11HtCap.transitionTime;
pHtcap->mcsFeedback = dot11HtCap.mcsFeedback;
pHtcap->txBF = dot11HtCap.txBF;
pHtcap->rxStaggeredSounding = dot11HtCap.rxStaggeredSounding;
pHtcap->txStaggeredSounding = dot11HtCap.txStaggeredSounding;
pHtcap->rxZLF = dot11HtCap.rxZLF;
pHtcap->txZLF = dot11HtCap.txZLF;
pHtcap->implicitTxBF = dot11HtCap.implicitTxBF;
pHtcap->calibration = dot11HtCap.calibration;
pHtcap->explicitCSITxBF = dot11HtCap.explicitCSITxBF;
pHtcap->explicitUncompressedSteeringMatrix =
dot11HtCap.explicitUncompressedSteeringMatrix;
pHtcap->explicitBFCSIFeedback = dot11HtCap.explicitBFCSIFeedback;
pHtcap->explicitUncompressedSteeringMatrixFeedback =
dot11HtCap.explicitUncompressedSteeringMatrixFeedback;
pHtcap->explicitCompressedSteeringMatrixFeedback =
dot11HtCap.explicitCompressedSteeringMatrixFeedback;
pHtcap->csiNumBFAntennae = dot11HtCap.csiNumBFAntennae;
pHtcap->uncompressedSteeringMatrixBFAntennae =
dot11HtCap.uncompressedSteeringMatrixBFAntennae;
pHtcap->compressedSteeringMatrixBFAntennae =
dot11HtCap.compressedSteeringMatrixBFAntennae;
pHtcap->antennaSelection = dot11HtCap.antennaSelection;
pHtcap->explicitCSIFeedbackTx = dot11HtCap.explicitCSIFeedbackTx;
pHtcap->antennaIndicesFeedbackTx = dot11HtCap.antennaIndicesFeedbackTx;
pHtcap->explicitCSIFeedback = dot11HtCap.explicitCSIFeedback;
pHtcap->antennaIndicesFeedback = dot11HtCap.antennaIndicesFeedback;
pHtcap->rxAS = dot11HtCap.rxAS;
pHtcap->txSoundingPPDUs = dot11HtCap.txSoundingPPDUs;
}
}
void limSendP2PActionFrame(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
tSirMbMsgP2p *pMbMsg = (tSirMbMsgP2p *)pMsg->bodyptr;
tANI_U32 nBytes;
tANI_U8 *pFrame;
void *pPacket;
eHalStatus halstatus;
tANI_U32 txFlag = 0;
tpSirMacFrameCtl pFc = (tpSirMacFrameCtl ) pMbMsg->data;
tANI_U8 noaLen = 0;
tANI_U8 noaStream[SIR_MAX_NOA_ATTR_LEN + (2*SIR_P2P_IE_HEADER_LEN)];
tANI_U8 origLen = 0;
tANI_U8 sessionId = 0;
v_U8_t *pP2PIe = NULL;
tpPESession psessionEntry;
v_U8_t *pPresenceRspNoaAttr = NULL;
v_U8_t *pNewP2PIe = NULL;
v_U16_t remainLen = 0;
nBytes = pMbMsg->msgLen - sizeof(tSirMbMsg);
limLog( pMac, LOG1, FL("sending pFc->type=%d pFc->subType=%d"),
pFc->type, pFc->subType);
psessionEntry = peFindSessionByBssid(pMac,
(tANI_U8*)pMbMsg->data + BSSID_OFFSET, &sessionId);
/* Check for session corresponding to ADDR2 As Supplicant is filling
ADDR2 with BSSID */
if( NULL == psessionEntry )
{
psessionEntry = peFindSessionByBssid(pMac,
(tANI_U8*)pMbMsg->data + ADDR2_OFFSET, &sessionId);
}
if( NULL == psessionEntry )
{
tANI_U8 isSessionActive = 0;
tANI_U8 i;
/* If we are not able to find psessionEntry entry, then try to find
active session, if found any active sessions then send the
action frame, If no active sessions found then drop the frame */
for (i =0; i < pMac->lim.maxBssId;i++)
{
psessionEntry = peFindSessionBySessionId(pMac,i);
if ( NULL != psessionEntry)
{
isSessionActive = 1;
break;
}
}
if( !isSessionActive )
{
limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF,
eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0);
return;
}
}
if ((SIR_MAC_MGMT_FRAME == pFc->type)&&
((SIR_MAC_MGMT_PROBE_RSP == pFc->subType)||
(SIR_MAC_MGMT_ACTION == pFc->subType)))
{
//if this is a probe RSP being sent from wpa_supplicant
if (SIR_MAC_MGMT_PROBE_RSP == pFc->subType)
{
//get proper offset for Probe RSP
pP2PIe = limGetP2pIEPtr(pMac,
(tANI_U8*)pMbMsg->data + PROBE_RSP_IE_OFFSET,
nBytes - PROBE_RSP_IE_OFFSET);
while ((NULL != pP2PIe) && (SIR_MAC_MAX_IE_LENGTH == pP2PIe[1]))
{
remainLen = nBytes - (pP2PIe - (tANI_U8*)pMbMsg->data);
if (remainLen > 2)
{
pNewP2PIe = limGetP2pIEPtr(pMac,
pP2PIe+SIR_MAC_MAX_IE_LENGTH + 2, remainLen);
}
if (pNewP2PIe)
{
pP2PIe = pNewP2PIe;
pNewP2PIe = NULL;
}
else
{
break;
}
} //end of while
}
else
{
if (SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY ==
*((v_U8_t *)pMbMsg->data+ACTION_OFFSET))
{
tpSirMacP2PActionFrameHdr pActionHdr =
(tpSirMacP2PActionFrameHdr)((v_U8_t *)pMbMsg->data +
ACTION_OFFSET);
if (vos_mem_compare( pActionHdr->Oui,
SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE ) &&
(SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP ==
pActionHdr->OuiSubType))
{ //In case of Presence RSP response
pP2PIe = limGetP2pIEPtr(pMac,
(v_U8_t *)pMbMsg->data + ACTION_OFFSET +
sizeof(tSirMacP2PActionFrameHdr),
(nBytes - ACTION_OFFSET -
sizeof(tSirMacP2PActionFrameHdr)));
if( NULL != pP2PIe )
{
//extract the presence of NoA attribute inside P2P IE
pPresenceRspNoaAttr =
limGetIEPtr(pMac,pP2PIe + SIR_P2P_IE_HEADER_LEN,
pP2PIe[1], SIR_P2P_NOA_ATTR,TWO_BYTE);
}
}
}
}
if (pP2PIe != NULL)
{
//get NoA attribute stream P2P IE
noaLen = limGetNoaAttrStream(pMac, noaStream, psessionEntry);
//need to append NoA attribute in P2P IE
if (noaLen > 0)
{
origLen = pP2PIe[1];
//if Presence Rsp has NoAttr
if (pPresenceRspNoaAttr)
{
v_U16_t noaAttrLen = pPresenceRspNoaAttr[1] |
(pPresenceRspNoaAttr[2]<<8);
/*One byte for attribute, 2bytes for length*/
origLen -= (noaAttrLen + 1 + 2);
//remove those bytes to copy
nBytes -= (noaAttrLen + 1 + 2);
//remove NoA from original Len
pP2PIe[1] = origLen;
}
if ((pP2PIe[1] + (tANI_U16)noaLen)> SIR_MAC_MAX_IE_LENGTH)
{
//Form the new NoA Byte array in multiple P2P IEs
noaLen = limGetNoaAttrStreamInMultP2pIes(pMac, noaStream,
noaLen,((pP2PIe[1] + (tANI_U16)noaLen)-
SIR_MAC_MAX_IE_LENGTH));
pP2PIe[1] = SIR_MAC_MAX_IE_LENGTH;
}
else
{
pP2PIe[1] += noaLen; //increment the length of P2P IE
}
nBytes += noaLen;
limLog( pMac, LOGE,
FL("noaLen=%d origLen=%d pP2PIe=%p"
" nBytes=%d nBytesToCopy=%zu"),
noaLen,origLen, pP2PIe, nBytes,
((pP2PIe + origLen + 2) - (v_U8_t *)pMbMsg->data));
}
}
if (SIR_MAC_MGMT_PROBE_RSP == pFc->subType)
{
limSetHtCaps( pMac, psessionEntry, (tANI_U8*)pMbMsg->data + PROBE_RSP_IE_OFFSET,
nBytes - PROBE_RSP_IE_OFFSET);
}
/* The minimum wait for any action frame should be atleast 100 ms.
* If supplicant sends action frame at the end of already running remain on channel time
* Then there is a chance to miss the response of the frame. So increase the remain on channel
* time for all action frame to make sure that we receive the response frame */
if ((SIR_MAC_MGMT_ACTION == pFc->subType) &&
(0 != pMbMsg->wait))
{
if (tx_timer_running(&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
tANI_U32 val = 0;
tx_timer_deactivate(&pMac->lim.limTimers.gLimRemainOnChannelTimer);
/* get the duration from the request */
pMac->lim.p2pRemOnChanTimeStamp = vos_timer_get_system_time();
pMac->lim.gTotalScanDuration = pMbMsg->wait;
val = SYS_MS_TO_TICKS(pMbMsg->wait);
limLog(pMac, LOG1,
FL("Tx: Extending the gLimRemainOnChannelTimer"));
if (tx_timer_change(
&pMac->lim.limTimers.gLimRemainOnChannelTimer, val, 0)
!= TX_SUCCESS)
{
limLog(pMac, LOGP,
FL("Unable to change remain on channel Timer val"));
return;
}
else if(TX_SUCCESS != tx_timer_activate(
&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
limLog(pMac, LOGP,
FL("Unable to activate remain on channel Timer"));
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
return;
}
}
else
{
limLog(pMac, LOGE,
FL("Failed to Send Action frame \n"));
limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF,
eHAL_STATUS_FAILURE, pMbMsg->sessionId, 0);
return;
}
}
}
// Ok-- try to allocate some memory:
halstatus = palPktAlloc( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
(tANI_U16)nBytes, ( void** ) &pFrame, (void**) &pPacket);
if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
{
limLog( pMac, LOGE, FL("Failed to allocate %d bytes for a Probe"
" Request."), nBytes );
return;
}
// Paranoia:
vos_mem_set(pFrame, nBytes, 0);
if ((noaLen > 0) && (noaLen<(SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)))
{
// Add 2 bytes for length and Arribute field
v_U32_t nBytesToCopy = ((pP2PIe + origLen + 2 ) -
(v_U8_t *)pMbMsg->data);
vos_mem_copy(pFrame, pMbMsg->data, nBytesToCopy);
vos_mem_copy((pFrame + nBytesToCopy), noaStream, noaLen);
vos_mem_copy((pFrame + nBytesToCopy + noaLen),
pMbMsg->data + nBytesToCopy, nBytes - nBytesToCopy - noaLen);
}
else
{
vos_mem_copy(pFrame, pMbMsg->data, nBytes);
}
/* Use BD rate 2 for all P2P related frames. As these frames need to go
* at OFDM rates. And BD rate2 we configured at 6Mbps.
*/
txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME;
if ( (SIR_MAC_MGMT_PROBE_RSP == pFc->subType) ||
(pMbMsg->noack)
)
{
halstatus = halTxFrame( pMac, pPacket, (tANI_U16)nBytes,
HAL_TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS,
7,/*SMAC_SWBD_TX_TID_MGMT_HIGH */ limTxComplete, pFrame,
txFlag );
if (!pMbMsg->noack)
{
limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF,
halstatus, pMbMsg->sessionId, 0);
}
pMac->lim.mgmtFrameSessionId = 0xff;
}
else
{
pMac->lim.mgmtFrameSessionId = 0xff;
halstatus = halTxFrameWithTxComplete( pMac, pPacket, (tANI_U16)nBytes,
HAL_TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS,
7,/*SMAC_SWBD_TX_TID_MGMT_HIGH */ limTxComplete, pFrame,
limP2PActionCnf, txFlag );
if ( ! HAL_STATUS_SUCCESS ( halstatus ) )
{
limLog( pMac, LOGE, FL("could not send action frame!" ));
limSendSmeRsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, halstatus,
pMbMsg->sessionId, 0);
pMac->lim.mgmtFrameSessionId = 0xff;
}
else
{
pMac->lim.mgmtFrameSessionId = pMbMsg->sessionId;
limLog( pMac, LOG2, FL("lim.actionFrameSessionId = %u" ),
pMac->lim.mgmtFrameSessionId);
}
}
return;
}
void limAbortRemainOnChan(tpAniSirGlobal pMac)
{
if(VOS_TRUE == tx_timer_running(
&pMac->lim.limTimers.gLimRemainOnChannelTimer))
{
//TODO check for state and take appropriate actions
limDeactivateAndChangeTimer(pMac, eLIM_REMAIN_CHN_TIMER);
limLog( pMac, LOG1, FL("Abort ROC !!!" ));
limProcessRemainOnChnTimeout(pMac);
}
return;
}
/* Power Save Related Functions */
tSirRetStatus __limProcessSmeNoAUpdate(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf)
{
tpP2pPsConfig pNoA;
tpP2pPsParams pMsgNoA;
tSirMsgQ msg;
pNoA = (tpP2pPsConfig) pMsgBuf;
pMsgNoA = vos_mem_malloc(sizeof( tP2pPsConfig ));
if (NULL == pMsgNoA)
{
limLog( pMac, LOGE,
FL( "Unable to allocate memory during NoA Update" ));
return eSIR_MEM_ALLOC_FAILED;
}
vos_mem_set((tANI_U8 *)pMsgNoA, sizeof(tP2pPsConfig), 0);
pMsgNoA->opp_ps = pNoA->opp_ps;
pMsgNoA->ctWindow = pNoA->ctWindow;
pMsgNoA->duration = pNoA->duration;
pMsgNoA->interval = pNoA->interval;
pMsgNoA->count = pNoA->count;
pMsgNoA->single_noa_duration = pNoA->single_noa_duration;
pMsgNoA->psSelection = pNoA->psSelection;
msg.type = WDA_SET_P2P_GO_NOA_REQ;
msg.reserved = 0;
msg.bodyptr = pMsgNoA;
msg.bodyval = 0;
if(eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg))
{
limLog(pMac, LOGE, FL("halPostMsgApi failed"));
return eSIR_FAILURE;
}
return eSIR_SUCCESS;
} /*** end __limProcessSmeGoNegReq() ***/