| /* |
| * Copyright (c) 2013, 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. |
| */ |
| |
| /**============================================================================= |
| |
| vos_list.c |
| |
| \brief |
| |
| Description... |
| |
| |
| Copyright 2008 (c) Qualcomm Technologies, Inc. |
| All Rights Reserved. |
| Qualcomm Technologies Confidential and Proprietary. |
| |
| ============================================================================== */ |
| /* $HEADER$ */ |
| #include "bapRsnTxRx.h" |
| #include "bapRsn8021xFsm.h" |
| #include "bapInternal.h" |
| #include "vos_trace.h" |
| #include "wlan_qct_tl.h" |
| #include "vos_memory.h" |
| |
| |
| static pnfTxCompleteHandler bapRsnFsmTxCmpHandler; |
| static pnfRxFrameHandler bapRsnFsmRxFrameHandler; |
| |
| extern int gReadToSetKey; |
| |
| |
| VOS_STATUS bapRsnRegisterTxRxCallbacks( pnfTxCompleteHandler pfnTxCom, pnfRxFrameHandler pnfRxFrame ) |
| { |
| if( bapRsnFsmTxCmpHandler || bapRsnFsmRxFrameHandler ) |
| { |
| return VOS_STATUS_E_ALREADY; |
| } |
| |
| bapRsnFsmTxCmpHandler = pfnTxCom; |
| bapRsnFsmRxFrameHandler = pnfRxFrame; |
| |
| return ( VOS_STATUS_SUCCESS ); |
| } |
| |
| void bapRsnClearTxRxCallbacks(void) |
| { |
| bapRsnFsmTxCmpHandler = NULL; |
| bapRsnFsmRxFrameHandler = NULL; |
| } |
| |
| |
| //To reserve a vos_packet for Tx eapol frame |
| //If success, pPacket is the packet and pData points to the head. |
| static VOS_STATUS bapRsnAcquirePacket( vos_pkt_t **ppPacket, v_U8_t **ppData, v_U16_t size ) |
| { |
| VOS_STATUS status; |
| vos_pkt_t *pPacket; |
| |
| status = vos_pkt_get_packet( &pPacket, VOS_PKT_TYPE_TX_802_11_MGMT, size, 1, |
| VOS_TRUE, NULL, NULL ); |
| if( VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| status = vos_pkt_reserve_head( pPacket, (v_VOID_t **)ppData, size ); |
| if( !VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "bapRsnAcquirePacket failed to reserve size = %d\n", size ); |
| vos_pkt_return_packet( pPacket ); |
| } |
| else |
| { |
| *ppPacket = pPacket; |
| } |
| } |
| else |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "bapRsnAcquirePacket failed to get vos_pkt\n" ); |
| } |
| |
| return ( status ); |
| } |
| |
| |
| static VOS_STATUS bapRsnTxCompleteCallback( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket, VOS_STATUS retStatus ) |
| { |
| int retVal; |
| ptBtampContext btampContext; // use btampContext value |
| tCsrRoamSetKey setKeyInfo; |
| tSuppRsnFsm *fsm; |
| |
| if (NULL == pvosGCtx) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "pvosGCtx is NULL in %s", __func__); |
| |
| return VOS_STATUS_E_FAULT; |
| } |
| |
| btampContext = VOS_GET_BAP_CB(pvosGCtx); |
| if (NULL == btampContext) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "btampContext is NULL in %s", __func__); |
| |
| return VOS_STATUS_E_FAULT; |
| } |
| |
| fsm = &btampContext->uFsm.suppFsm; |
| if (NULL == fsm) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "fsm is NULL in %s", __func__); |
| |
| return VOS_STATUS_E_FAULT; |
| } |
| |
| //If we get a disconect from upper layer before getting the pkt from TL the |
| //bapRsnFsmTxCmpHandler could be NULL |
| //VOS_ASSERT( bapRsnFsmTxCmpHandler ); |
| |
| if( bapRsnFsmTxCmpHandler ) |
| { |
| //Change the state |
| //Call auth or supp FSM's handler |
| bapRsnFsmTxCmpHandler( pvosGCtx, pPacket, retStatus ); |
| } |
| else |
| { |
| vos_pkt_return_packet( pPacket ); |
| return (VOS_STATUS_SUCCESS ); |
| } |
| |
| //fsm->suppCtx->ptk contains the 3 16-bytes keys. We need the last one. |
| /* |
| We will move the Set key to EAPOL Completion handler. We found a race condition betweem |
| sending EAPOL frame and setting Key */ |
| if (BAP_SET_RSN_KEY == gReadToSetKey) { |
| vos_mem_zero( &setKeyInfo, sizeof( tCsrRoamSetKey ) ); |
| setKeyInfo.encType = eCSR_ENCRYPT_TYPE_AES; |
| setKeyInfo.keyDirection = eSIR_TX_RX; |
| vos_mem_copy( setKeyInfo.peerMac, fsm->suppCtx->authMac, sizeof( tAniMacAddr ) ); |
| setKeyInfo.paeRole = 0; //this is a supplicant |
| setKeyInfo.keyId = 0; //always |
| setKeyInfo.keyLength = CSR_AES_KEY_LEN; |
| vos_mem_copy( setKeyInfo.Key, (v_U8_t *)fsm->suppCtx->ptk + (2 * CSR_AES_KEY_LEN ), CSR_AES_KEY_LEN ); |
| |
| if( !VOS_IS_STATUS_SUCCESS( bapSetKey( fsm->ctx->pvosGCtx, &setKeyInfo ) ) ) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, " Supp: gotoStateStaKeySet fail to set key\n" ); |
| retVal = ANI_ERROR; |
| } |
| gReadToSetKey = BAP_RESET_RSN_KEY; |
| } |
| |
| return (VOS_STATUS_SUCCESS ); |
| } |
| |
| |
| static VOS_STATUS bapRsnTxFrame( v_PVOID_t pvosGCtx, vos_pkt_t *pPacket ) |
| { |
| VOS_STATUS status; |
| WLANTL_MetaInfoType metaInfo; |
| |
| vos_mem_zero( &metaInfo, sizeof( WLANTL_MetaInfoType ) ); |
| metaInfo.ucIsEapol = 1; //only send eapol frame |
| status = WLANTL_TxBAPFrm( pvosGCtx, pPacket, &metaInfo, bapRsnTxCompleteCallback ); |
| if( !VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "bapRsnTxFrame failed to send vos_pkt status = %d\n", status ); |
| } |
| |
| return ( status ); |
| } |
| |
| |
| /* |
| \brief bapRsnSendEapolFrame |
| To push an eapol frame to TL. |
| |
| \param pAniPkt - a ready eapol frame that is prepared in tAniPacket format |
| */ |
| VOS_STATUS bapRsnSendEapolFrame( v_PVOID_t pvosGCtx, tAniPacket *pAniPkt ) |
| { |
| VOS_STATUS status; |
| vos_pkt_t *pPacket; |
| v_U8_t *pData, *pSrc; |
| int pktLen = aniAsfPacketGetBytes( pAniPkt, &pSrc ); |
| |
| if( pktLen <= 0 ) |
| { |
| return VOS_STATUS_E_EMPTY; |
| } |
| status = bapRsnAcquirePacket( &pPacket, &pData, pktLen ); |
| if( VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| vos_mem_copy( pData, pSrc, pktLen ); |
| //Send the packet, need to check whether we have an outstanding packet first. |
| status = bapRsnTxFrame( pvosGCtx, pPacket ); |
| if( !VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| vos_pkt_return_packet( pPacket ); |
| } |
| } |
| |
| return ( status ); |
| } |
| |
| |
| //TL call this function on Rx frames, should only be EAPOL frames |
| VOS_STATUS bapRsnRxCallback( v_PVOID_t pv, vos_pkt_t *pPacket ) |
| { |
| //Callback to auth or supp FSM's handler |
| VOS_ASSERT( bapRsnFsmRxFrameHandler ); |
| if( bapRsnFsmRxFrameHandler ) |
| { |
| bapRsnFsmRxFrameHandler( pv, pPacket ); |
| } |
| else |
| { |
| //done |
| vos_pkt_return_packet( pPacket ); |
| } |
| |
| return ( VOS_STATUS_SUCCESS ); |
| } |
| |
| |
| |
| VOS_STATUS bapRsnRegisterRxCallback( v_PVOID_t pvosGCtx ) |
| { |
| VOS_STATUS status; |
| |
| status = WLANTL_RegisterBAPClient( pvosGCtx, WLANBAP_RxCallback, WLANBAP_TLFlushCompCallback ); |
| if( !VOS_IS_STATUS_SUCCESS( status ) ) |
| { |
| if( VOS_STATUS_E_EXISTS != status ) |
| { |
| VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, |
| "bapRsnRegisterRxCallback failed with status = %d\n", status ); |
| } |
| else |
| { |
| //We consider it ok to register it multiple times because only BAP's RSN should call this |
| status = VOS_STATUS_SUCCESS; |
| } |
| } |
| |
| return ( status ); |
| } |
| |
| |