一、實驗目的
1、了解主從配對綁定的過程中底層是怎麼運作的;
二、說明
1、關于配對于綁定,網上查了很多資料都沒查到什麼,問了很多人也沒有回答的,是以我決定自己深入了解底層關于配對與綁定是如何運作的,我用了接近兩個星期來了解的,效率很低,在這裡總結一下,希望能幫助到别人。
2.這裡之是大概講了一個方向,因為涉及的點太多,無法一一列出,需要研究細節的,自己去探讨一下,不懂可以在群上讨論
三、實驗平台
1、藍牙協定棧:1.3.2
2、軟體平台:IAR For 8051 8.10.3
5、硬體平台:Smart RF開發闆(從機),Android_Lightblue(主機)
四、實驗步驟
1.static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
case GAP_LINK_ESTABLISHED_EVENT:
if ( pPkt->hdr.status == SUCCESS )
{
// Notify the Bond Manager to the connection //通知綁定管理調出綁定目前連接配接主機的綁定資訊如LTK等
VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFIL E_PERIPHERAL );
}
}
2.bStatus_t GAPBondMgr_LinkEst( uint8 addrType, uint8 *pDevAddr, uint16 connHandle, uint8 role )
{
idx = GAPBondMgr_ResolveAddr( addrType, pDevAddr, publicAddr );//檢視目前連接配接的主機是否綁定過
if ( idx < GAP_BONDINGS_MAX ) //如果目前連接配接主機在NV的某個位置(綁定過)則将綁定資訊調出,否則不管
{
// On peripheral, load the key information for the bonding 從機加載出綁定的密鑰資訊
// On central and initiaiting security, load key to initiate encyption 主機加載出綁定的密鑰資訊并向從機發出加密請求
gapBondMgrBondReq( connHandle, idx, stateFlags, role,
((gapBond_PairingMode == GAPBOND_PAIRING_MODE_INITIATE ) ? TRUE : FALSE) )
// If Peripheral and initiating, send a slave security request to initiate either pairing or encryption
//調用出綁定資訊後,向主機發出安全請求,主機發起加密或配對(如果沒綁定過)
if ( role == GAP_PROFILE_PERIPHERAL &&
gapBond_PairingMode == GAPBOND_PAIRING_MODE_INITIATE )
{
gapBondMgrSlaveSecurityReq( connHandle ); //向主機發送安全請求
}
}
3.等待主機發送配對(沒綁定)或加密請求(綁定過)
一、沒綁定過
1.static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
GAP_PAIRING_REQ_EVENT: //接收到主機的配對請求
{
// Send pairing response //配對響應
gapBondMgrAuthenticate( pPkt->connectionHandle, pLinkItem->addrType, &(pPkt->pairReq) ); //啟動認證
}
}
}
2.static void gapBondMgrAuthenticate( uint16 connHandle, uint8 addrType,gapPairingReq_t *pPairReq )
{
VOID GAP_Authenticate( ¶ms, pPairReq ); //認證,根據配對請求接收到的主機資訊(如主機的配對能力等)跟自己的配對能力做比較然後執行下一步動作(由于從機設定成GAPBOND_IO_CAP_DISPLAY_ONLY,是以主機索求密碼)
}
3.static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
case GAP_PASSKEY_NEEDED_EVENT: //向主機索求密碼
{
if ( pGapBondCB && pGapBondCB->passcodeCB ) //用回調函數發送密碼請求
{
// Ask app for a passcode
pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs );
}
}
}
4.static void ProcessPasscodeCB(uint8 *deviceAddr,uint16 connectionHandle,uint8 uiInputs,uint8 uiOutputs )
{
passcode = 123456; //使用固定密碼123456
// Send passcode response
GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, passcode ); //發送密碼請求給主機
}
5.等待主機回複密碼,從機接收到主機的密碼回複後,在底層對接收到的密碼做校驗,要麼密碼不正确(status=SMP_PAIRING_FAILED_CONFIRM_VALUE),要麼正确(status=SUCCESS),要麼主機取消輸入操作(status=SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED),在校驗密碼完成後,從機觸發GAP_AUTHENTICATION_COMPLETE_EVENT事件并向主機發送自己的認證資訊TLK等(認證成功)或發送認證status=Msg Buffer Not Available(密碼錯誤),發送消息是底層完成的,不開源;
6.static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
case GAP_AUTHENTICATION_COMPLETE_EVENT: //認證完成
{
if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) )//判斷認證是否成功
{
// Save off of the authentication state
VOID gapBondMgrAddBond( &bondRec, //綁定
(gapBondLTK_t *)pPkt->pSecurityInfo,
(gapBondLTK_t *)pPkt->pDevSecInfo,
((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )),
((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )),
((uint32)((pPkt->pSigningInfo)?pPkt->pSigningInfo->signCounter :GAP_INIT_SIGN_COUNTER ))
}
// Call app state callback
if ( pGapBondCB && pGapBondCB->pairStateCB ) //通知回調函數目前認證的狀态,密碼正确或不正确
{
pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status );
}
}
}
二、綁定過
1.主機接收到從機的安全請求後,會檢查目前連接配接的從機是否綁定過,綁定過的話,利用綁定的資訊做加密并向從機發送加密請求;
2.從機接收到主機的加密請求後,用GAP_LINK_ESTABLISHED_EVENT中的調出來的綁定資訊跟主機進行三次加密握手(底層完成),如果加密成功,從機向主機發送綁定完成事件(status=SUCCESS)并觸發GAP_BOND_COMPLETE_EVENT事件,如果加密不成功(從機删除綁定資訊),從機向主機發送綁定完成事件(status=LL_REJECT_IND)事件但不觸發GAP_BOND_COMPLETE_EVENT事件
3.static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
case GAP_BOND_COMPLETE_EVENT: //綁定完成
#if ( HOST_CONFIG & CENTRAL_CFG ) //主機
if ( pPkt->hdr.status == LL_ENC_KEY_REQ_REJECTED ) //如果加密失敗且status =LL_ENC_KEY_REQ_REJECTED
{
switch ( gapBond_BondFailOption ) //當綁定過,但是加密失敗的時候,主機可以啟動重新配對
{
case GAPBOND_FAIL_INITIATE_PAIRING:
// Initiate pairing
gapBondMgrAuthenticate( pPkt->connectionHandle, pLinkItem->addrType, NULL );
break;
}
}
}
#endif
if ( pGapBondCB && pGapBondCB->pairStateCB ) //加密成功,通知回調函數
{
pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status );
}
}
}
}
五、總結
1.每次連接配接後,從機都會向主機發送安全請求gapBondMgrSlaveSecurityReq( connHandle ),如果沒有互相綁定過,主機會發起配對(配對資料中包括主機的密鑰等),配對完成後,從機觸發GAP_AUTHENTICATION_COMPLETE_EVENT并向主機發送自己的認證資訊LTK等,這樣互相儲存認證資訊LTK等後就算綁定了;
2.每次連接配接後,從機都會向主機發送安全請求gapBondMgrSlaveSecurityReq( connHandle ),如果配對綁定過,主機和從機會以儲存下來的認證資訊LTK等來做加密認證,如果加密成,從機觸發GAP_BOND_COMPLETE_EVENT事件并向主機發送綁定完成消息(status=0x00)SUCCESS,如果認證失敗(從機删除綁定資訊),從機會向主機發送綁定完成消息(status=0x06)LL_REJECT_IND事件當不觸發GAP_BOND_COMPLETE_EVENT事件;
六、補充
1.問題一:從機跟主機配對過一次後,不會再次配對;
答:從機跟主機配對過後,互相儲存綁定的認證資訊,當再次連接配接時,主機先會去檢查目前從機是否綁定過,如果有,就不會在發起配對了,即使是從機更改了配對密碼也是一樣,因為再次連接配接加密認證時是用儲存好的綁定資訊(LTK)來做加密認證的,而不是配對密碼,配對密碼隻是臨時密碼(TK),用來在配對時産生LTK的,如果不用配對,更改配對密碼是沒有任何意義的;
2.問題二:主從機如何删除綁定?
答:主機:在手機的系統藍牙設定裡面有取消配對;
從機:GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS,0, NULL ); 這個函數可以删除所有綁定,但前提它不會立即執行,它要先确認從機目前是在連接配接狀态還是在無連接配接狀态,無連接配接狀态時,删除綁定是立即執行,連接配接狀态時,需要等斷開連接配接後自動執行,詳情可以自己看一下這個函數的代碼就好,想在連接配接狀态下删除綁定可以直接用gapBondMgrEraseAllBondings(),想删除某個綁定可以用gapBondMgrEraseBonding();
3.問題三:為什麼從機删除綁定後,IOS lightblue 不會重新配對,android lightblue會重新配對,IOS lightblue隻有在系統藍牙中取消配對在可以重新配對;
答:上面的實驗步驟二.2講到在從機删除綁定後,主機再和從機連接配接時,最終會加密失敗,從機會發送失敗消息給主機,主機可以在接收到加密失敗消息後重新啟動配對,像二.3一樣,至于IOS lightblue 不會重新配對,android lightblue會重新配對,那隻是APP程式編寫不同而已了;
4.很多人問為什麼在阿莫資料中的藍牙4.0連接配接之配對與綁定實驗中,OLED顯示bonding success 是在配對後的第二次連接配接才會顯示
答:依總結.2看來,第一次配對綁定并不會觸發GAP_BOND_COMPLETE_EVENT事件的,而阿莫的OLED顯示bonding success 就是放在GAP_BOND_COMPLETE_EVENT事件,,是以第一次配對OLED不會顯示bonding success,在主從配對綁定後,每次連接配接時,如果加密成功都會觸發GAP_BOND_COMPLETE_EVENT事件,是以在配對之後的第一次連接配接才會顯示bonding success,實際上綁定相當與儲存認證資訊而已,在GAP_AUTHENTICATION_COMPLETE_EVENT中gapBondMgrAddBond就已經做了,你也可以在GAP_AUTHENTICATION_COMPLETE_EVENT事件中做OLED顯示bonding success ;