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

689 lines
20 KiB
C

/*************************************************************************************************
Filename: smp.c
Revised:
Revision:
Description: This file contains the Security Manager Protocol.
SDK_LICENSE
**************************************************************************************************/
#include "bcomdef.h"
#include "OSAL.h"
#include "osal_bufmgr.h"
#include "hci.h"
#include "l2cap.h"
#include "gap.h"
#include "sm.h"
#include "sm_internal.h"
#include "smp.h"
/*********************************************************************
MACROS
*/
/*********************************************************************
CONSTANTS
*/
// Pairing Request & Response - Key Distribution Field - bit mask
// These are used to break up byte in to keyDist_t
#define SMP_KEYDIST_ENCKEY 0x01
#define SMP_KEYDIST_IDKEY 0x02
#define SMP_KEYDIST_SIGN 0x04
/*********************************************************************
TYPEDEFS
*/
/*********************************************************************
GLOBAL VARIABLES
*/
/*********************************************************************
EXTERNAL VARIABLES
*/
/*********************************************************************
EXTERNAL FUNCTIONS
*/
/*********************************************************************
LOCAL VARIABLES
*/
/*********************************************************************
FUNCTIONS
*/
/*********************************************************************
@fn smpBuildPairingReq
@brief Build an SM Pairing Request
@param pPairingReq - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingReq is NULL
*/
bStatus_t smpBuildPairingReq( smpPairingReq_t* pPairingReq, uint8* pBuf )
{
return ( smpBuildPairingReqRsp( SMP_PAIRING_REQ, pPairingReq, pBuf ) );
}
/*********************************************************************
@fn smpBuildPairingRsp
@brief Build an SM Pairing Response
@param pPairingRsp - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingRsp is NULL
*/
bStatus_t smpBuildPairingRsp( smpPairingReq_t* pPairingRsp, uint8* pBuf )
{
return ( smpBuildPairingReqRsp( SMP_PAIRING_RSP, pPairingRsp, pBuf ) );
}
/*********************************************************************
@fn smpBuildPairingReqRsp
@brief Build an SM Pairing Request or Response
@param code - either SMP_PAIRING_REQ or SMP_PAIRING_RSP
@param pPairingReq - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingReq is NULL
*/
bStatus_t smpBuildPairingReqRsp( uint8 opCode, smpPairingReq_t* pPairingReq, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingReq == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = opCode;
*pBuf++ = pPairingReq->ioCapability;
*pBuf++ = pPairingReq->oobDataFlag;
*pBuf++ = smAuthReqToUint8( &(pPairingReq->authReq) );
*pBuf++ = pPairingReq->maxEncKeySize;
*pBuf = (pPairingReq->keyDist.mEncKey) ? (SMP_KEYDIST_ENCKEY) : 0;
*pBuf |= (pPairingReq->keyDist.mIdKey) ? (SMP_KEYDIST_IDKEY) : 0;
*pBuf |= (pPairingReq->keyDist.mSign) ? (SMP_KEYDIST_SIGN) : 0;
*pBuf |= (pPairingReq->keyDist.mReserved) << 3; // HZF: fixed bug 2018-11-27, recover reserved bits(5bits in BLE4.0)
pBuf++;
*pBuf = (pPairingReq->keyDist.sEncKey) ? (SMP_KEYDIST_ENCKEY) : 0;
*pBuf |= (pPairingReq->keyDist.sIdKey) ? (SMP_KEYDIST_IDKEY) : 0;
*pBuf |= (pPairingReq->keyDist.sSign) ? (SMP_KEYDIST_SIGN) : 0;
*pBuf |= (pPairingReq->keyDist.sReserved) << 3; // HZF: fixed bug 2018-11-27, recover reserved bits(5bits in BLE4.0)
return ( SUCCESS );
}
/*********************************************************************
@fn smpParsePairingReq
@brief Parse an SM Pairing Request
@param pBuf - data buffer to parse
@param pPairingReq - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingReq is NULL
bleInvalidRange if a generic field is out of range
bleIncorrectMode if enc key is out of range
*/
bStatus_t smpParsePairingReq( uint8* pBuf, smpPairingReq_t* pPairingReq )
{
uint8 tmp;
// Check pointers
if ( (pBuf == NULL) || (pPairingReq == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
pPairingReq->ioCapability = *pBuf++;
pPairingReq->oobDataFlag = *pBuf++;
smUint8ToAuthReq( &(pPairingReq->authReq), *pBuf++ );
pPairingReq->maxEncKeySize = *pBuf++;
tmp = *pBuf++;
pPairingReq->keyDist.mEncKey = (tmp & SMP_KEYDIST_ENCKEY) ? TRUE : FALSE;
pPairingReq->keyDist.mIdKey = (tmp & SMP_KEYDIST_IDKEY) ? TRUE : FALSE;
pPairingReq->keyDist.mSign = (tmp & SMP_KEYDIST_SIGN) ? TRUE : FALSE;
pPairingReq->keyDist.mReserved = (tmp & 0xF8)>>3; // HZF: fixed bug 2018-11-27, saved reserved bits(5bits in BLE4.0)
tmp = *pBuf;
pPairingReq->keyDist.sEncKey = (tmp & SMP_KEYDIST_ENCKEY) ? TRUE : FALSE;
pPairingReq->keyDist.sIdKey = (tmp & SMP_KEYDIST_IDKEY) ? TRUE : FALSE;
pPairingReq->keyDist.sSign = (tmp & SMP_KEYDIST_SIGN) ? TRUE : FALSE;
pPairingReq->keyDist.sReserved = (tmp & 0xF8)>>3; // HZF: fixed bug 2018-11-27, saved reserved bits(5bits in BLE4.0)
// Check the encryption key size
if ( (pPairingReq->maxEncKeySize < GAP_GetParamValue( TGAP_SM_MIN_KEY_LEN ))
|| (pPairingReq->maxEncKeySize > GAP_GetParamValue( TGAP_SM_MAX_KEY_LEN )) )
{
return ( bleIncorrectMode );
}
// Check for range of fields
if ( (pPairingReq->ioCapability > SMP_IO_CAP_KEYBOARD_DISPLAY)
|| (pPairingReq->oobDataFlag > SMP_OOB_AUTH_DATA_REMOTE_DEVICE_PRESENT) )
{
return ( bleInvalidRange );
}
else
{
return ( SUCCESS );
}
}
/*********************************************************************
@fn smpBuildPairingConfirm
@brief Build an SM Pairing Confirm
@param pPairingConfirm - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingConfirm is NULL
*/
bStatus_t smpBuildPairingConfirm( smpPairingConfirm_t* pPairingConfirm,
uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingConfirm == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_PAIRING_CONFIRM;
VOID osal_memcpy( pBuf, pPairingConfirm->confirmValue, SMP_CONFIRM_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParsePairingConfirm
@brief Parse an SM Pairing Confirm
@param pBuf - data buffer to build into
@param pPairingConfirm - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingConfirm is NULL
*/
bStatus_t smpParsePairingConfirm( uint8* pBuf,
smpPairingConfirm_t* pPairingConfirm )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingConfirm == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
VOID osal_memcpy( pPairingConfirm->confirmValue, pBuf, SMP_CONFIRM_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildPairingRandom
@brief Build an SM Pairing Random
@param pPairingRandom - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingRandom is NULL
*/
bStatus_t smpBuildPairingRandom( smpPairingRandom_t* pPairingRandom,
uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingRandom == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_PAIRING_RANDOM;
VOID osal_memcpy( pBuf, pPairingRandom->randomValue, SMP_RANDOM_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParsePairingRandom
@brief Parse an SM Pairing Random
@param pBuf - data buffer to build into
@param pPairingRandom - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingRandom is NULL
*/
bStatus_t smpParsePairingRandom( uint8* pBuf,
smpPairingRandom_t* pPairingRandom )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingRandom == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
VOID osal_memcpy( pPairingRandom->randomValue, pBuf, SMP_RANDOM_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildPairingFailed
@brief Build an SM Pairing Failed
@param pPairingFailed - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingFailed is NULL
*/
bStatus_t smpBuildPairingFailed( smpPairingFailed_t* pPairingFailed,
uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingFailed == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_PAIRING_FAILED;
*pBuf = pPairingFailed->reason;
return ( SUCCESS );
}
/*********************************************************************
@fn smpParsePairingFailed
@brief Parse an SM Pairing Failed
@param pBuf - data buffer to build into
@param pPairingFailed - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or pairingFailed is NULL
bleInvalidRange if the reason field is out of range
*/
bStatus_t smpParsePairingFailed( uint8* pBuf,
smpPairingFailed_t* pPairingFailed )
{
// Check pointers
if ( (pBuf == NULL) || (pPairingFailed == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
pPairingFailed->reason = *pBuf;
// Reason range check
if ( pPairingFailed->reason > SMP_PAIRING_FAILED_REPEATED_ATTEMPTS
|| (pPairingFailed->reason == 0) )
{
return ( bleInvalidRange );
}
else
{
return ( SUCCESS );
}
}
/*********************************************************************
@fn smpBuildEncInfo
@brief Build an SM Encryption Information
@param pEncInfo - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildEncInfo( smpEncInfo_t* pEncInfo, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pEncInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_ENCRYPTION_INFORMATION;
VOID osal_memcpy( pBuf, pEncInfo->ltk, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseEncInfo
@brief Parse an SM Encryption Information
@param pBuf - data buffer to build into
@param pEncInfo - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseEncInfo( uint8* pBuf, smpEncInfo_t* pEncInfo )
{
// Check pointers
if ( (pBuf == NULL) || (pEncInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
VOID osal_memcpy( pEncInfo->ltk, pBuf, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildMasterID
@brief Build an SM Master Identification
@param pMasterID - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildMasterID( smpMasterID_t* pMasterID, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pMasterID == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_MASTER_IDENTIFICATION;
*pBuf++ = LO_UINT16( pMasterID->ediv );
*pBuf++ = HI_UINT16( pMasterID->ediv );
VOID osal_memcpy( pBuf, pMasterID->rand, B_RANDOM_NUM_SIZE );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseMasterID
@brief Parse an SM Master Identification
@param pBuf - data buffer to build into
@param pMasterID - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseMasterID( uint8* pBuf, smpMasterID_t* pMasterID )
{
// Check pointers
if ( (pBuf == NULL) || (pMasterID == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
pMasterID->ediv = BUILD_UINT16( pBuf[0], pBuf[1] );
VOID osal_memcpy( pMasterID->rand, &pBuf[2], B_RANDOM_NUM_SIZE );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildIdentityInfo
@brief Build an SM Identity Information
@param pIdInfo - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildIdentityInfo( smpIdentityInfo_t* pIdInfo, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pIdInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_IDENTITY_INFORMATION;
VOID osal_memcpy( pBuf, pIdInfo->irk, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildIdentityAddrInfo
@brief Build an SM Identity Address Information
@param pIdInfo - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildIdentityAddrInfo( smpIdentityAddrInfo_t* pIdInfo, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pIdInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_IDENTITY_ADDR_INFORMATION;
*pBuf++ = pIdInfo->addrType;
VOID osal_memcpy( pBuf, pIdInfo->bdAddr, B_ADDR_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseIdentityInfo
@brief Parse an SM Identity Information
@param pBuf - data buffer to build into
@param pIdInfo - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseIdentityInfo( uint8* pBuf, smpIdentityInfo_t* pIdInfo )
{
// Check pointers
if ( (pBuf == NULL) || (pIdInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
VOID osal_memcpy( pIdInfo->irk, pBuf, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseIdentityAddrInfo
@brief Parse an SM Identity Address Information
@param pBuf - data buffer to build into
@param pIdInfo - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseIdentityAddrInfo( uint8* pBuf, smpIdentityAddrInfo_t* pIdInfo )
{
// Check pointers
if ( (pBuf == NULL) || (pIdInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
pIdInfo->addrType = *pBuf++;
VOID osal_memcpy( pIdInfo->bdAddr, pBuf, B_ADDR_LEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildSigningInfo
@brief Build an SM Signing Information
@param pSigningInfo - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildSigningInfo( smpSigningInfo_t* pSigningInfo, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pSigningInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_SIGNING_INFORMATION;
VOID osal_memcpy( pBuf, pSigningInfo->signature, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseSigningInfo
@brief Parse an SM Signing Information
@param pBuf - data buffer to build into
@param pSigningInfo - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseSigningInfo( uint8* pBuf, smpSigningInfo_t* pSigningInfo )
{
// Check pointers
if ( (pBuf == NULL) || (pSigningInfo == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
VOID osal_memcpy( pSigningInfo->signature, pBuf, KEYLEN );
return ( SUCCESS );
}
/*********************************************************************
@fn smpBuildSecurityReq
@brief Build an SM Slave Security Request
@param pSecReq - pointer to structure.
@param pBuf - data buffer to build into
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpBuildSecurityReq( smpSecurityReq_t* pSecReq, uint8* pBuf )
{
// Check pointers
if ( (pBuf == NULL) || (pSecReq == NULL) )
{
return ( INVALIDPARAMETER );
}
*pBuf++ = SMP_SECURITY_REQUEST;
*pBuf = smAuthReqToUint8( &(pSecReq->authReq) );
return ( SUCCESS );
}
/*********************************************************************
@fn smpParseSecurityReq
@brief Parse an SM Slave Security Request
@param pBuf - data buffer to build into
@param pSecReq - pointer to structure.
@return SUCCESS if parsed
INVALIDPARAMETER if buf or struct ptr is NULL
*/
bStatus_t smpParseSecurityReq( uint8* pBuf, smpSecurityReq_t* pSecReq )
{
// Check pointers
if ( (pBuf == NULL) || (pSecReq == NULL) )
{
return ( INVALIDPARAMETER );
}
pBuf++; // Skip code
smUint8ToAuthReq( &(pSecReq->authReq), *pBuf );
return ( SUCCESS );
}
/*********************************************************************
@fn smSendSMMsg
@brief Allocate send buffer, build the SM message and send
the message to L2CAP.
@param connHandle - Connection to send message
@param bufLen - Length of buffer needed
@param pMsg - message structure
@param buildFn - function pointer to build function
@return status
*/
bStatus_t smSendSMMsg( uint16 connHandle, uint8 bufLen, smpMsgs_t* pMsg, pfnSMBuildCmd_t buildFn )
{
bStatus_t stat;
l2capPacket_t sendData;
// Allocate a buffer
sendData.CID = L2CAP_CID_SMP;
sendData.len = bufLen;
sendData.pPayload = (uint8*)L2CAP_bm_alloc( sendData.len );
if ( sendData.pPayload )
{
stat = buildFn( pMsg, sendData.pPayload );
if ( stat == SUCCESS )
{
stat = L2CAP_SendData( connHandle, &sendData );
}
if ( stat != SUCCESS )
{
osal_bm_free( sendData.pPayload );
}
}
else
{
stat = bleMemAllocError;
}
// TODO : if stat is not success , start sm tsp timer is there any problem ?
// Start the SM Timeout
smStartRspTimer(connHandle);
return ( stat );
}