| /* |
| * Copyright (c) 2012-2014,2016 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. |
| */ |
| |
| |
| |
| |
| #include "sme_Api.h" |
| #include "smsDebug.h" |
| #include "csrInsideApi.h" |
| #include "smeInside.h" |
| #include "p2p_Api.h" |
| #include "cfgApi.h" |
| #include "wma.h" |
| |
| |
| eHalStatus p2pProcessNoAReq(tpAniSirGlobal pMac, tSmeCmd *pNoACmd); |
| |
| /** |
| * csr_release_roc_req_cmd() - Release the command |
| * @mac_ctx: Global MAC Context |
| * |
| * Release the remain on channel request command from the queue |
| * |
| * Return: None |
| */ |
| void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx) |
| { |
| tListElem *entry = NULL; |
| tSmeCmd *cmd = NULL; |
| |
| entry = csrLLPeekHead(&mac_ctx->sme.smeCmdActiveList, LL_ACCESS_LOCK); |
| if (entry) { |
| cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); |
| if (eSmeCommandRemainOnChannel == cmd->command) { |
| remainOnChanCallback callback = |
| cmd->u.remainChlCmd.callback; |
| /* process the msg */ |
| if (callback) |
| callback(mac_ctx, |
| cmd->u.remainChlCmd.callbackCtx, 0); |
| smsLog(mac_ctx, LOGE, |
| FL("Remove RoC Request from Active Cmd List")); |
| /* Now put this cmd back on the avilable command list */ |
| if (csrLLRemoveEntry(&mac_ctx->sme.smeCmdActiveList, |
| entry, LL_ACCESS_LOCK)) |
| smeReleaseCommand(mac_ctx, cmd); |
| } |
| } |
| } |
| |
| /*------------------------------------------------------------------ |
| * |
| * handle SME remain on channel request. |
| * |
| *------------------------------------------------------------------*/ |
| |
| eHalStatus p2pProcessRemainOnChannelCmd(tpAniSirGlobal pMac, tSmeCmd *p2pRemainonChn) |
| { |
| eHalStatus status = eHAL_STATUS_FAILURE; |
| tSirRemainOnChnReq* pMsg; |
| tANI_U32 len; |
| tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, p2pRemainonChn->sessionId ); |
| |
| if(!pSession) |
| { |
| smsLog(pMac, LOGE, FL(" session %d not found "), p2pRemainonChn->sessionId); |
| goto error; |
| } |
| |
| |
| if(!pSession->sessionActive) |
| { |
| smsLog(pMac, LOGE, FL(" session %d is invalid or listen is disabled "), |
| p2pRemainonChn->sessionId); |
| goto error; |
| } |
| len = sizeof(tSirRemainOnChnReq) + pMac->p2pContext.probeRspIeLength; |
| |
| if( len > 0xFFFF ) |
| { |
| /*In coming len for Msg is more then 16bit value*/ |
| smsLog(pMac, LOGE, FL(" Message length is very large, %d"), |
| len); |
| goto error; |
| } |
| |
| pMsg = vos_mem_malloc(len); |
| if ( NULL == pMsg ) |
| goto error; |
| else |
| { |
| VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, "%s call", __func__); |
| vos_mem_set(pMsg, sizeof(tSirRemainOnChnReq), 0); |
| pMsg->messageType = eWNI_SME_REMAIN_ON_CHANNEL_REQ; |
| pMsg->length = (tANI_U16)len; |
| vos_mem_copy(pMsg->selfMacAddr, pSession->selfMacAddr, sizeof(tSirMacAddr)); |
| pMsg->chnNum = p2pRemainonChn->u.remainChlCmd.chn; |
| pMsg->phyMode = p2pRemainonChn->u.remainChlCmd.phyMode; |
| pMsg->duration = p2pRemainonChn->u.remainChlCmd.duration; |
| pMsg->sessionId = p2pRemainonChn->sessionId; |
| pMsg->isProbeRequestAllowed = p2pRemainonChn->u.remainChlCmd.isP2PProbeReqAllowed; |
| if( pMac->p2pContext.probeRspIeLength ) |
| vos_mem_copy((void *)pMsg->probeRspIe, (void *)pMac->p2pContext.probeRspIe, |
| pMac->p2pContext.probeRspIeLength); |
| status = palSendMBMessage(pMac->hHdd, pMsg); |
| } |
| error: |
| if (eHAL_STATUS_FAILURE == status) |
| csr_release_roc_req_cmd(pMac); |
| return status; |
| } |
| |
| |
| /*------------------------------------------------------------------ |
| * |
| * handle LIM remain on channel rsp: Success/failure. |
| * |
| *------------------------------------------------------------------*/ |
| |
| eHalStatus sme_remainOnChnRsp( tpAniSirGlobal pMac, tANI_U8 *pMsg) |
| { |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tListElem *pEntry = NULL; |
| tSmeCmd *pCommand = NULL; |
| tANI_BOOLEAN fFound; |
| tSirSmeRsp *pRsp = (tSirSmeRsp *)pMsg; |
| |
| if (pMac->fP2pListenOffload) |
| pEntry = csrLLPeekHead(&pMac->sme.smeScanCmdActiveList, LL_ACCESS_LOCK); |
| else |
| pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); |
| if( pEntry ) |
| { |
| pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); |
| if( eSmeCommandRemainOnChannel == pCommand->command ) |
| { |
| remainOnChanCallback callback = pCommand->u.remainChlCmd.callback; |
| /* process the msg */ |
| if( callback ) |
| callback(pMac, pCommand->u.remainChlCmd.callbackCtx, |
| pRsp->statusCode); |
| |
| if (pMac->fP2pListenOffload) |
| { |
| fFound = csrLLRemoveEntry( &pMac->sme.smeScanCmdActiveList, |
| pEntry, LL_ACCESS_LOCK); |
| } |
| else |
| { |
| fFound = csrLLRemoveEntry( &pMac->sme.smeCmdActiveList, pEntry, |
| LL_ACCESS_LOCK); |
| } |
| |
| if (fFound) |
| { |
| /* Now put this command back on the available command list */ |
| smeReleaseCommand(pMac, pCommand); |
| } |
| smeProcessPendingQueue( pMac ); |
| } |
| } |
| return status; |
| } |
| |
| /*------------------------------------------------------------------ |
| * |
| * Handle the remain on channel ready indication from PE |
| * |
| *------------------------------------------------------------------*/ |
| |
| eHalStatus sme_remainOnChnReady( tHalHandle hHal, tANI_U8* pMsg) |
| { |
| tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tListElem *pEntry = NULL; |
| tSmeCmd *pCommand = NULL; |
| tCsrRoamInfo RoamInfo; |
| |
| if (pMac->fP2pListenOffload) |
| pEntry = csrLLPeekHead(&pMac->sme.smeScanCmdActiveList, LL_ACCESS_LOCK); |
| else |
| pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); |
| |
| if( pEntry ) |
| { |
| pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); |
| if( eSmeCommandRemainOnChannel == pCommand->command ) |
| { |
| |
| /* forward the indication to HDD */ |
| RoamInfo.pRemainCtx = pCommand->u.remainChlCmd.callbackCtx; |
| csrRoamCallCallback(pMac, ((tSirSmeRsp*)pMsg)->sessionId, &RoamInfo, |
| 0, eCSR_ROAM_REMAIN_CHAN_READY, 0); |
| } |
| } |
| |
| return status; |
| } |
| |
| eHalStatus sme_p2pOpen( tHalHandle hHal ) |
| { |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| |
| //If static structure is too big, Need to change this function to allocate memory dynamically |
| vos_mem_zero(&pMac->p2pContext, sizeof( tp2pContext )); |
| |
| if(!HAL_STATUS_SUCCESS(status)) |
| { |
| sme_p2pClose(hHal); |
| } |
| |
| return status; |
| } |
| |
| |
| eHalStatus p2pStop( tHalHandle hHal ) |
| { |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| |
| if( pMac->p2pContext.probeRspIe ) |
| { |
| vos_mem_free(pMac->p2pContext.probeRspIe); |
| pMac->p2pContext.probeRspIe = NULL; |
| } |
| |
| pMac->p2pContext.probeRspIeLength = 0; |
| |
| return eHAL_STATUS_SUCCESS; |
| } |
| |
| |
| eHalStatus sme_p2pClose( tHalHandle hHal ) |
| { |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| |
| if( pMac->p2pContext.probeRspIe ) |
| { |
| vos_mem_free(pMac->p2pContext.probeRspIe); |
| pMac->p2pContext.probeRspIe = NULL; |
| } |
| |
| pMac->p2pContext.probeRspIeLength = 0; |
| |
| return eHAL_STATUS_SUCCESS; |
| } |
| |
| |
| tSirRFBand GetRFBand(tANI_U8 channel) |
| { |
| if ((channel >= SIR_11A_CHANNEL_BEGIN) && |
| (channel <= SIR_11A_CHANNEL_END)) |
| return SIR_BAND_5_GHZ; |
| |
| if ((channel >= SIR_11B_CHANNEL_BEGIN) && |
| (channel <= SIR_11B_CHANNEL_END)) |
| return SIR_BAND_2_4_GHZ; |
| |
| return SIR_BAND_UNKNOWN; |
| } |
| |
| /* --------------------------------------------------------------------------- |
| |
| \fn p2pRemainOnChannel |
| \brief API to post the remain on channel command. |
| \param hHal - The handle returned by macOpen. |
| \param sessinId - HDD session ID. |
| \param channel - Channel to remain on channel. |
| \param duration - Duration for which we should remain on channel |
| \param callback - callback function. |
| \param pContext - argument to the callback function |
| \return eHalStatus |
| |
| -------------------------------------------------------------------------------*/ |
| eHalStatus p2pRemainOnChannel(tHalHandle hHal, tANI_U8 sessionId, |
| tANI_U8 channel, tANI_U32 duration, |
| remainOnChanCallback callback, |
| void *pContext, tANI_U8 isP2PProbeReqAllowed |
| ) |
| { |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| tSmeCmd *pRemainChlCmd = NULL; |
| tANI_U32 phyMode; |
| |
| pRemainChlCmd = smeGetCommandBuffer(pMac); |
| if(pRemainChlCmd == NULL) |
| return eHAL_STATUS_FAILURE; |
| |
| if (SIR_BAND_5_GHZ == GetRFBand(channel)) |
| { |
| phyMode = WNI_CFG_PHY_MODE_11A; |
| } |
| else |
| { |
| phyMode = WNI_CFG_PHY_MODE_11G; |
| } |
| |
| cfgSetInt(pMac, WNI_CFG_PHY_MODE, phyMode); |
| |
| do |
| { |
| /* call set in context */ |
| pRemainChlCmd->command = eSmeCommandRemainOnChannel; |
| pRemainChlCmd->sessionId = sessionId; |
| pRemainChlCmd->u.remainChlCmd.chn = channel; |
| pRemainChlCmd->u.remainChlCmd.duration = duration; |
| pRemainChlCmd->u.remainChlCmd.isP2PProbeReqAllowed = isP2PProbeReqAllowed; |
| pRemainChlCmd->u.remainChlCmd.callback = callback; |
| pRemainChlCmd->u.remainChlCmd.callbackCtx = pContext; |
| |
| //Put it at the head of the Q if we just finish finding the peer and ready to send a frame |
| status = csrQueueSmeCommand(pMac, pRemainChlCmd, eANI_BOOLEAN_FALSE); |
| } while(0); |
| |
| smsLog(pMac, LOGW, "exiting function %s", __func__); |
| |
| return(status); |
| } |
| |
| eHalStatus p2pSendAction(tHalHandle hHal, tANI_U8 sessionId, |
| const tANI_U8 *pBuf, tANI_U32 len, tANI_U16 wait, tANI_BOOLEAN noack) |
| { |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| tSirMbMsgP2p *pMsg; |
| tANI_U16 msgLen; |
| |
| VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED, |
| " %s sends action frame", __func__); |
| msgLen = (tANI_U16)((sizeof( tSirMbMsg )) + len); |
| pMsg = vos_mem_malloc(msgLen); |
| if ( NULL == pMsg ) |
| status = eHAL_STATUS_FAILURE; |
| else |
| { |
| vos_mem_set((void *)pMsg, msgLen, 0); |
| pMsg->type = pal_cpu_to_be16((tANI_U16)eWNI_SME_SEND_ACTION_FRAME_IND); |
| pMsg->msgLen = pal_cpu_to_be16(msgLen); |
| pMsg->sessionId = sessionId; |
| pMsg->noack = noack; |
| pMsg->wait = (tANI_U16)wait; |
| vos_mem_copy(pMsg->data, pBuf, len); |
| status = palSendMBMessage(pMac->hHdd, pMsg); |
| } |
| |
| return( status ); |
| } |
| |
| eHalStatus p2pCancelRemainOnChannel(tHalHandle hHal, tANI_U8 sessionId) |
| { |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tpAniSirGlobal pMac = PMAC_STRUCT(hHal); |
| tSirMbMsgP2p *pMsg; |
| tANI_U16 msgLen; |
| |
| //Need to check session ID to support concurrency |
| |
| msgLen = (tANI_U16)(sizeof( tSirMbMsg )); |
| pMsg = vos_mem_malloc(msgLen); |
| if ( NULL == pMsg ) |
| status = eHAL_STATUS_FAILURE; |
| else |
| { |
| vos_mem_set((void *)pMsg, msgLen, 0); |
| pMsg->type = pal_cpu_to_be16((tANI_U16)eWNI_SME_ABORT_REMAIN_ON_CHAN_IND); |
| pMsg->msgLen = pal_cpu_to_be16(msgLen); |
| pMsg->sessionId = sessionId; |
| status = palSendMBMessage(pMac->hHdd, pMsg); |
| } |
| |
| return( status ); |
| } |
| |
| eHalStatus p2pSetPs(tHalHandle hHal, tP2pPsConfig *pNoA) |
| { |
| tpP2pPsConfig pNoAParam; |
| tSirMsgQ msg; |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); |
| |
| pNoAParam = vos_mem_malloc(sizeof(tP2pPsConfig)); |
| if ( NULL == pNoAParam ) |
| status = eHAL_STATUS_FAILURE; |
| else |
| { |
| vos_mem_set(pNoAParam, sizeof(tP2pPsConfig), 0); |
| vos_mem_copy(pNoAParam, pNoA, sizeof(tP2pPsConfig)); |
| msg.type = eWNI_SME_UPDATE_NOA; |
| msg.bodyval = 0; |
| msg.bodyptr = pNoAParam; |
| limPostMsgApi(pMac, &msg); |
| } |
| return status; |
| } |
| |
| |
| eHalStatus p2pProcessNoAReq(tpAniSirGlobal pMac, tSmeCmd *pNoACmd) |
| { |
| tpP2pPsConfig pNoA; |
| tSirMsgQ msg; |
| eHalStatus status = eHAL_STATUS_SUCCESS; |
| |
| pNoA = vos_mem_malloc(sizeof(tP2pPsConfig)); |
| if ( NULL == pNoA ) |
| status = eHAL_STATUS_FAILURE; |
| else |
| { |
| vos_mem_set(pNoA, sizeof(tP2pPsConfig), 0); |
| pNoA->opp_ps = pNoACmd->u.NoACmd.NoA.opp_ps; |
| pNoA->ctWindow = pNoACmd->u.NoACmd.NoA.ctWindow; |
| pNoA->duration = pNoACmd->u.NoACmd.NoA.duration; |
| pNoA->interval = pNoACmd->u.NoACmd.NoA.interval; |
| pNoA->count = pNoACmd->u.NoACmd.NoA.count; |
| pNoA->single_noa_duration = pNoACmd->u.NoACmd.NoA.single_noa_duration; |
| pNoA->psSelection = pNoACmd->u.NoACmd.NoA.psSelection; |
| pNoA->sessionid = pNoACmd->u.NoACmd.NoA.sessionid; |
| msg.type = eWNI_SME_UPDATE_NOA; |
| msg.bodyval = 0; |
| msg.bodyptr = pNoA; |
| limPostMsgApi(pMac, &msg); |
| } |
| return status; |
| } |