THB2/bthome_phy6222/SDK/lib/ble_host/sm_intpairing.c

870 lines
31 KiB
C

/*************************************************************************************************
Filename: sm_intpairing.c
Revised:
Revision:
Description: This file contains the SM Initiator Pairing Manager.
SDK_LICENSE
**************************************************************************************************/
/*******************************************************************************
INCLUDES
*/
#include "bcomdef.h"
#include "l2cap.h"
#include "gap_internal.h"
#include "linkdb.h"
#include "sm.h"
#include "sm_internal.h"
#include "smp.h"
#include "osal_cbtimer.h"
/*********************************************************************
MACROS
*/
/*********************************************************************
CONSTANTS
*/
/*********************************************************************
TYPEDEFS
*/
/*********************************************************************
GLOBAL VARIABLES
*/
/*********************************************************************
EXTERNAL VARIABLES
*/
extern uint8 smState_CBTimer[];
/*********************************************************************
EXTERNAL FUNCTIONS
*/
/*********************************************************************
LOCAL VARIABLES
*/
/*********************************************************************
LOCAL FUNCTIONS
*/
static uint8 smpInitiatorProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg );
static uint8 smpInitiatorProcessPairingRsp( uint16 connectionHandle,smpPairingRsp_t* parsedMsg );
static uint8 smpInitiatorProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg );
static uint8 smpInitiatorProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg );
static uint8 smpInitiatorProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg );
static uint8 smpInitiatorProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg );
static uint8 smpInitiatorProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg );
static uint8 smpInitiatorProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg );
static uint8 smpInitiatorProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg );
static void setupInitiatorKeys( uint16 connectionHandle );
static void smInitiatorSendNextKeyInfo( uint16 connectionHandle );
/*********************************************************************
INITIATOR CALLBACKS
*/
// SM Initiator Callbacks
static smInitiatorCBs_t smInitiatorCBs =
{
smpInitiatorProcessIncoming, // Process SMP Message Callback
smInitiatorSendNextKeyInfo, // Send Next Key Message Callback
SM_StartEncryption // Start Encrypt Callback
};
/*********************************************************************
API FUNCTIONS
*/
/*********************************************************************
FUNCTIONS - MASTER API - Only use these in a master device
*/
/*********************************************************************
Initialize SM Initiator on a master device.
Public function defined in sm.h.
*/
bStatus_t SM_InitiatorInit( void )
{
if ( gapProfileRole & GAP_PROFILE_CENTRAL )
{
// Set up Initiator's processing function
smRegisterInitiator( &smInitiatorCBs );
}
else
{
smRegisterInitiator( NULL );
}
return ( SUCCESS );
}
/*********************************************************************
@fn smEncLTK
@brief Start LKT Encryption on an Initiator.
@param none
@return none
*/
void smEncLTK( uint16 connectionHandle )
{
// Make sure we are in the right state
if ( (pPairingParams[connectionHandle]) && (pPairingParams[connectionHandle]->initiator)
&& (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_ENCRYPT)
&& (pPairingParams[connectionHandle]->pDevEncParams) )
{
if ( SM_StartEncryption( pPairingParams[connectionHandle]->connectionHandle,
pPairingParams[connectionHandle]->pDevEncParams->ltk,
pPairingParams[connectionHandle]->pDevEncParams->div,
pPairingParams[connectionHandle]->pDevEncParams->rand,
pPairingParams[connectionHandle]->pDevEncParams->keySize ) != SUCCESS )
{
// Start encryption failed
smEndPairing( connectionHandle,SMP_PAIRING_FAILED_UNSPECIFIED );
}
}
}
/*********************************************************************
@fn SM_StartEncryption
@brief Send Start Encrypt through HCI
@param connHandle - Connection Handle
@param pLTK - pointer to 16 byte lkt
@param div - div or ediv
@param pRandNum - pointer to 8 byte random number
@param keyLen - length of LTK (bytes)
@return SUCCESS
INVALIDPARAMETER
other from HCI/LL
*/
bStatus_t SM_StartEncryption( uint16 connHandle, uint8* pLTK, uint16 div, uint8* pRandNum, uint8 keyLen )
{
uint8 eDiv[2]; // LTK div
uint8 key[KEYLEN]; // LTK
uint8 random[B_RANDOM_NUM_SIZE]; // LTK Random
// check the parameters
if ( pLTK == NULL )
{
return ( INVALIDPARAMETER );
}
// Setup encryption parameters
eDiv[0] = LO_UINT16( div );
eDiv[1] = HI_UINT16( div );
VOID osal_memset( key, 0, KEYLEN );
VOID osal_memcpy( key, pLTK, keyLen );
// A null randNum means to build a random number of all zero's
if ( pRandNum )
{
VOID osal_memcpy( random, pRandNum, B_RANDOM_NUM_SIZE );
}
else
{
VOID osal_memset( random, 0, B_RANDOM_NUM_SIZE );
}
return ( HCI_LE_StartEncyptCmd( connHandle, random, eDiv, key ) );
}
/*********************************************************************
@fn smpInitiatorProcessIncoming
@brief Process incoming parsed SM Initiator message.
@param pLinkItem - connection information
@param cmdID - command ID
@param pParsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED
SMP_PAIRING_FAILED_OOB_NOT_AVAIL
SMP_PAIRING_FAILED_AUTH_REQ
SMP_PAIRING_FAILED_CONFIRM_VALUE
SMP_PAIRING_FAILED_NOT_SUPPORTED
SMP_PAIRING_FAILED_ENC_KEY_SIZE
SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED
SMP_PAIRING_FAILED_UNSPECIFIED
SMP_PAIRING_FAILED_REPEATED_ATTEMPTS
*/
static uint8 smpInitiatorProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg )
{
uint8 reason = SUCCESS; // return value
// check for pairing mode
if ( pPairingParams[pLinkItem->connectionHandle] == NULL )
{
if ( cmdID == SMP_SECURITY_REQUEST )
{
// Notify app/profile
gapSendSlaveSecurityReqEvent( pLinkItem->taskID, pLinkItem->connectionHandle,
pLinkItem->addr, smAuthReqToUint8( &(pParsedMsg->secReq.authReq) ) );
return ( SUCCESS );
}
else
{
// Ignore the message, don't respond
return ( SUCCESS );
}
}
// We can only handle one pairing at a time
if ( pPairingParams[pLinkItem->connectionHandle]->connectionHandle != pLinkItem->connectionHandle )
{
return ( SMP_PAIRING_FAILED_UNSPECIFIED );
}
if ( pPairingParams[pLinkItem->connectionHandle]->initiator == FALSE )
{
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
// Process the pairing messages
switch ( cmdID )
{
case SMP_PAIRING_RSP:
reason = smpInitiatorProcessPairingRsp( pLinkItem->connectionHandle,(smpPairingRsp_t*)pParsedMsg );
break;
case SMP_PAIRING_CONFIRM:
reason = smpInitiatorProcessPairingConfirm( pLinkItem->connectionHandle,(smpPairingConfirm_t*)pParsedMsg );
break;
case SMP_PAIRING_RANDOM:
reason = smpInitiatorProcessPairingRandom( pLinkItem->connectionHandle,(smpPairingRandom_t*)pParsedMsg );
break;
case SMP_ENCRYPTION_INFORMATION:
reason = smpInitiatorProcessEncryptionInformation( pLinkItem->connectionHandle,(smpEncInfo_t*)pParsedMsg );
break;
case SMP_MASTER_IDENTIFICATION:
reason = smpInitiatorProcessMasterID( pLinkItem->connectionHandle,(smpMasterID_t*)pParsedMsg );
break;
case SMP_IDENTITY_INFORMATION:
reason = smpInitiatorProcessIdentityInfo( pLinkItem->connectionHandle,(smpIdentityInfo_t*)pParsedMsg );
break;
case SMP_IDENTITY_ADDR_INFORMATION:
reason = smpInitiatorProcessIdentityAddrInfo( pLinkItem->connectionHandle,(smpIdentityAddrInfo_t*)pParsedMsg );
break;
case SMP_SIGNING_INFORMATION:
reason = smpInitiatorProcessSigningInfo( pLinkItem->connectionHandle,(smpSigningInfo_t*)pParsedMsg );
break;
case SMP_SECURITY_REQUEST:
if ( pPairingParams[pLinkItem->connectionHandle] )
{
// We are currently pairing. Ignore the message, don't respond
return ( SUCCESS );
}
break;
case SMP_PAIRING_FAILED:
smEndPairing( pLinkItem->connectionHandle,pParsedMsg->pairingFailed.reason );
break;
default:
reason = SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED;
break;
}
return ( reason );
}
/*********************************************************************
@fn smpInitiatorProcessPairingRsp
@brief Process incoming parsed Pairing Response.
@param pParsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED
SMP_PAIRING_FAILED_UNSPECIFIED
SMP_PAIRING_FAILED_AUTH_REQ
*/
static uint8 smpInitiatorProcessPairingRsp( uint16 connectionHandle,smpPairingRsp_t* pParsedMsg )
{
uint8 reason = SUCCESS; // return value
bStatus_t stat; // status field
// Save the response information into pPairingParams[connectionHandle]
stat = smSavePairInfo( connectionHandle,pParsedMsg );
if ( stat == SUCCESS )
{
// Check for bonding
if ( (pPairingParams[connectionHandle]->pSecReqs->authReq & SM_AUTH_STATE_BONDING)
&& (pPairingParams[connectionHandle]->pPairDev->authReq.bonding == SM_AUTH_REQ_BONDING) )
{
pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_BONDING;
}
if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS)
|| (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS)
|| (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS) )
{
uint8 type;
// Determine the passkey input/output user requirements
if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS)
|| (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS) )
{
type = SM_PASSKEY_TYPE_INPUT;
}
else
{
type = SM_PASSKEY_TYPE_DISPLAY;
}
// Ask the app for passkey
gapPasskeyNeededCB( pPairingParams[connectionHandle]->connectionHandle, type );
pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED;
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_PASSKEY;
}
else if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_JUST_WORKS)
|| (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_OOB) )
{
// Get ready for the Confirm
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM;
// Initialize TK space
VOID osal_memset( pPairingParams[connectionHandle]->tk, 0, KEYLEN );
// Setup TK
if ( pPairingParams[connectionHandle]->type != SM_PAIRING_TYPE_JUST_WORKS )
{
// OOB
VOID osal_memcpy( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->pSecReqs->oob, KEYLEN );
pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED;
}
// Generate Rand (MRand)
smGenerateRandBuf( pPairingParams[connectionHandle]->myComp.rand, SMP_RANDOM_LEN );
// Generate Confirm (MConfirm)
sm_c1( connectionHandle,pPairingParams[connectionHandle]->tk,
pPairingParams[connectionHandle]->myComp.rand,
pPairingParams[connectionHandle]->myComp.confirm );
#if defined ( TESTMODES )
if ( GAP_GetParamValue( TGAP_SM_TESTCODE ) == SM_TESTMODE_SEND_BAD_CONFIRM )
{
VOID osal_memset( pPairingParams[connectionHandle]->myComp.confirm, 0, KEYLEN );
}
#endif // TESTMODE
if ( smGenerateConfirm( connectionHandle) != SUCCESS )
{
reason = SMP_PAIRING_FAILED_UNSPECIFIED;
}
}
}
else if ( stat == bleInvalidRange )
{
reason = SMP_PAIRING_FAILED_AUTH_REQ;
}
else
{
reason = SMP_PAIRING_FAILED_UNSPECIFIED;
}
return ( reason );
}
/*********************************************************************
@fn smpInitiatorProcessPairingConfirm
@brief Process incoming parsed Pairing Confirm.
@param pParsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg )
{
uint8 reason = SUCCESS; // return value
VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.confirm, pParsedMsg->confirmValue, KEYLEN );
// Received Responder Confirm, send Rand message
if ( smGenerateRandMsg(connectionHandle) != SUCCESS )
{
reason = SMP_PAIRING_FAILED_UNSPECIFIED;
}
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_RANDOM;
return ( reason );
}
/*********************************************************************
@fn smpInitiatorProcessPairingRandom
@brief Process incoming parsed Pairing Random.
@param parsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_CONFIRM_VALUE
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg )
{
uint8 reason = SUCCESS; // return value
uint8 confirm[KEYLEN]; // working area to calculate a confirm value
VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.rand, pParsedMsg->randomValue, SMP_RANDOM_LEN );
// Check device's Confirm value
sm_c1(connectionHandle, pPairingParams[connectionHandle]->tk,
pPairingParams[connectionHandle]->devComp.rand,
confirm );
// Make sure that the calculated confirm matches the confirm from the other device
if ( osal_memcmp( confirm, pPairingParams[connectionHandle]->devComp.confirm, KEYLEN ) == TRUE )
{
uint8 stk[KEYLEN]; // a place to generate the STK
// Received Responder, generate STK
if ( sm_s1( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->devComp.rand,
pPairingParams[connectionHandle]->myComp.rand, stk ) == SUCCESS )
{
// Start Encrypt with STK
if ( SM_StartEncryption( pPairingParams[connectionHandle]->connectionHandle,
stk, 0, 0, smDetermineKeySize( connectionHandle) ) != SUCCESS )
{
reason = SMP_PAIRING_FAILED_UNSPECIFIED;
}
}
else
{
reason = SMP_PAIRING_FAILED_UNSPECIFIED;
}
// Wait for STK to finish
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_STK;
}
else
{
reason = SMP_PAIRING_FAILED_CONFIRM_VALUE;
}
return ( reason );
}
/*********************************************************************
@fn smpInitiatorProcessEncryptionInformation
@brief Process incoming parsed Encryption Information.
@param pParsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg )
{
if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO )
{
// Save off the connected device's encryption information (LTK and key size)
if ( pPairingParams[connectionHandle]->pDevEncParams == NULL )
{
pPairingParams[connectionHandle]->pDevEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) );
}
if ( pPairingParams[connectionHandle]->pDevEncParams )
{
VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->ltk, pParsedMsg->ltk, KEYLEN );
pPairingParams[connectionHandle]->pDevEncParams->keySize = smDetermineKeySize( connectionHandle);
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO;
return ( SUCCESS );
}
}
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
/*********************************************************************
@fn smpInitiatorProcessMasterID
@brief Process incoming parsed Master Identification.
@param parsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg )
{
if ( (pPairingParams[connectionHandle]->pDevEncParams != NULL)
&& (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO) )
{
// Save off the rest of the connected device's encryption information
pPairingParams[connectionHandle]->pDevEncParams->div = pParsedMsg->ediv;
VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->rand, pParsedMsg->rand, B_RANDOM_NUM_SIZE );
// Setup the next state
if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sIdKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sIdKey) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO;
}
else if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sSign) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO;
}
else
{
setupInitiatorKeys(connectionHandle);
}
return ( SUCCESS );
}
else
{
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
}
/*********************************************************************
@fn smpInitiatorProcessIdentityInfo
@brief Process incoming parsed Identity Information.
@param parsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg )
{
if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO )
{
// Save off the info
if ( pPairingParams[connectionHandle]->pIdInfo == NULL )
{
pPairingParams[connectionHandle]->pIdInfo = (smIdentityInfo_t*)osal_mem_alloc( (uint16)sizeof (smIdentityInfo_t ) );
}
if ( pPairingParams[connectionHandle]->pIdInfo )
{
VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->irk, pParsedMsg->irk, KEYLEN );
}
// Determine next state
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO;
return ( SUCCESS );
}
else
{
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
}
/*********************************************************************
@fn smpInitiatorProcessIdentityAddrInfo
@brief Process incoming parsed Identity Address Information.
@param pParsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg )
{
if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO )
{
VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->bd_addr, pParsedMsg->bdAddr, B_ADDR_LEN );
// Determine the next state
if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sSign) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO;
}
else
{
// Start sending initiator (master) keys
setupInitiatorKeys(connectionHandle);
}
return ( SUCCESS );
}
else
{
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
}
/*********************************************************************
@fn smpInitiatorProcessSigningInfo
@brief Process incoming parsed Signing Information.
@param parsedMsg - pointer to parsed message
@return SUCCESS
SMP_PAIRING_FAILED_UNSPECIFIED
*/
static uint8 smpInitiatorProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg )
{
if ( pPairingParams[connectionHandle] )
{
if ( pPairingParams[connectionHandle]->pSigningInfo == NULL )
{
pPairingParams[connectionHandle]->pSigningInfo = (smSigningInfo_t*)osal_mem_alloc( (uint16)sizeof( smSigningInfo_t ) );
if ( pPairingParams[connectionHandle]->pSigningInfo == NULL )
{
// Only error available for memory error, this will end the pairing process
return ( SMP_PAIRING_FAILED_UNSPECIFIED );
}
}
// Copy signature information
if ( pPairingParams[connectionHandle]->pSigningInfo )
{
VOID osal_memcpy( pPairingParams[connectionHandle]->pSigningInfo->srk, pParsedMsg->signature, KEYLEN );
pPairingParams[connectionHandle]->pSigningInfo->signCounter = GAP_INIT_SIGN_COUNTER;
}
// Send the initiator key messages
setupInitiatorKeys(connectionHandle);
return ( SUCCESS );
}
else
{
return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED );
}
}
/*********************************************************************
@fn setupInitiatorKeys
@brief Setup Initiator Key distribution
@param none
@return none
*/
static void setupInitiatorKeys( uint16 connectionHandle )
{
if ( ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mEncKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mEncKey))
|| ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mIdKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mIdKey))
|| ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mSign)) )
{
// Setup to send initiator key messages
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_STK;
smInitiatorSendNextKeyInfo(connectionHandle);
}
else
{
// No keys to send
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE;
}
if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_DONE )
{
smEndPairing( connectionHandle,SUCCESS );
}
}
/*********************************************************************
@fn smInitiatorSendNextKeyInfo
@brief Initiator role: sends next key message, and sets state
for next event.
@param none
@return none
*/
static void smInitiatorSendNextKeyInfo( uint16 connectionHandle )
{
if ( pPairingParams[connectionHandle]->initiator == TRUE )
{
smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs;
smpPairingReq_t* pPairReq = pPairingParams[connectionHandle]->pPairDev;
uint8 state = pPairingParams[connectionHandle]->state;
// Determine key to send
if ( state == SM_PAIRING_STATE_WAIT_STK )
{
if ( (pPairReq->keyDist.mEncKey) && (pSecReq->keyDist.mEncKey) )
{
state = SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO;
}
else if ( (pPairReq->keyDist.mIdKey) && (pSecReq->keyDist.mIdKey) )
{
state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO;
}
else if ( (pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) )
{
state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO;
}
}
// Send the correct message
switch ( state )
{
case SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO:
// send Encryption Information.
if ( pPairingParams[connectionHandle]->pEncParams == NULL )
{
pPairingParams[connectionHandle]->pEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) );
if ( pPairingParams[connectionHandle]->pEncParams )
{
VOID osal_memset( pPairingParams[connectionHandle]->pEncParams, 0, sizeof (smSecurityInfo_t ) );
}
}
if ( pPairingParams[connectionHandle]->pEncParams )
{
smSecurityInfo_t* pEnc = pPairingParams[connectionHandle]->pEncParams;
// Default the key size to the key size of this encryption session.
if ( pEnc->keySize == 0 )
{
pEnc->keySize = smDetermineKeySize( connectionHandle);
}
// For now, temp random the LTK, EDIV and RAND
VOID osal_memset( pEnc->ltk, 0, KEYLEN );
smGenerateRandBuf( pEnc->ltk, pPairingParams[connectionHandle]->pEncParams->keySize );
pEnc->div = osal_rand();
smGenerateRandBuf( pEnc->rand, B_RANDOM_NUM_SIZE );
// Send the Encryption Info
smPairingSendEncInfo( pPairingParams[connectionHandle]->connectionHandle, pEnc->ltk );
}
break;
case SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO:
if ( pPairingParams[connectionHandle]->pEncParams )
{
smPairingSendMasterID( pPairingParams[connectionHandle]->connectionHandle,
pPairingParams[connectionHandle]->pEncParams->div,
pPairingParams[connectionHandle]->pEncParams->rand );
}
break;
case SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO:
smPairingSendIdentityInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetIRK() );
break;
case SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO:
{
uint8 getRealAddr = TRUE;
uint8 addrType = gapGetDevAddressMode();
if ( addrType == ADDRTYPE_STATIC )
{
getRealAddr = FALSE;
}
else
{
addrType = ADDRTYPE_PUBLIC;
}
smPairingSendIdentityAddrInfo( pPairingParams[connectionHandle]->connectionHandle,
addrType, gapGetDevAddress( getRealAddr ) );
}
break;
case SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO:
smPairingSendSingingInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetSRK() );
break;
default:
break;
}
// Determine the next state
if ( state == SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO;
}
else if ( state == SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO )
{
if ( (pPairReq->keyDist.mIdKey) && (pSecReq->keyDist.mIdKey) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO;
}
else if ((pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO;
}
else
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE;
}
}
else if ( state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO;
}
else if ( state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO )
{
if ( (pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) )
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO;
}
else
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE;
}
}
else
{
pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE;
}
if ( (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO)
|| (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO)
|| (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO)
|| (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO)
|| (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO) )
{
linkDBItem_t* linkItem;
uint32 timeout;
linkItem = linkDB_Find( pPairingParams[connectionHandle]->connectionHandle );
if ( linkItem != NULL )
{
// Make the timeout 1.5 * connInterval (connInterval = 1.25 ms)
timeout = linkItem->connInterval;
timeout += linkItem->connInterval / 2;
}
else
{
timeout = SM_PAIRING_STATE_WAIT;
}
// Set up the next send
smState_CBTimer[connectionHandle] = connectionHandle;
osal_CbTimerStart( smState_timerCB, &smState_CBTimer[connectionHandle],timeout, &pPairingParams[connectionHandle]->stateID );
}
}
}
/*********************************************************************
*********************************************************************/