1. 程式人生 > >BLE4.0配對繫結過程的底層剖析

BLE4.0配對繫結過程的底層剖析

一、實驗目的

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 ;
--------------------- 
作者:紅-蘿蔔 
來源:CSDN 
原文:https://blog.csdn.net/zhuangjitongxue/article/details/49745113 
版權宣告:本文為博主原創文章,轉載請附上博文連結!