This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-CC26X2R1: Fail to resolve RPA with after importing bonding via gapBondMgrImportBond()

Part Number: LAUNCHXL-CC26X2R1

Hi all,

in my project I want to import a bonding on to the CC26x2 device. The CC26x2 shall be a central device and resolve RPAs of undirected scannable advertisements. I can read out the Identity Adress and IRK of the pairing, where I want to substitute the central device.

For this, in accordance with the User Guides Bond Manager Import Bonding Information and Privacy sections, I use the gapBondMgrImportBond() function, in combination the White List Sync option  GAPBOND_AUTO_SYNC_WL actiated and with the filter policy SCAN_PARAM_FLT_POLICY set to SCAN_FLT_POLICY_WL as seen below.

For a minimal example which I couldn't get to work the code below is inserted in the simple_central example project in the simple_central.c file in the GAP_DEVICE_INIT_DONE_EVENT switch case of the SimpleCentral_processGapMsg function.

       uint8_t result_t;
        temp8 = SCAN_FLT_POLICY_WL;
        result_t = GapScan_setParam(SCAN_PARAM_FLT_POLICY, &temp8);
        if (result_t == SUCCESS)
        {
            Display_printf(dispHandle, 30, 0, "SCAN_FLT_POLICY_WL SET SUCCESS",
                           NULL);
        }
        else
        {
            Display_printf(dispHandle, 30, 0, "SCAN_FLT_POLICY_WL SET FAIL",
                           NULL);
        }

        uint8_t sync_WL = TRUE;
        result_t = GAPBondMgr_SetParameter(GAPBOND_AUTO_SYNC_WL,
                                           sizeof(uint8_t), &sync_WL);

        if (result_t == SUCCESS)
        {
            Display_printf(dispHandle, 31, 0,
                           "GAPBOND_AUTO_SYNC_WL SET SUCCESS", NULL);
        }
        else
        {
            Display_printf(dispHandle, 31, 0, "GAPBOND_AUTO_SYNC_WL SET FAIL",
                           NULL);
        }

        // Import Bonding
        // Parameters needed for storing bonding information.
        gapBondRec_t pSavedBondRec;
        gapBondLTK_t pLocalLtk;
        gapBondLTK_t pPeerLtk;
        uint8_t pPeerIRK[KEYLEN];
        uint8_t pPeerSRK[KEYLEN];
        uint32_t pPeerSignCount;
        gapBondCharCfg_t charCfg;

//                   pSavedBondRec.addr[0] = 0xF4;
//                   pSavedBondRec.addr[1] = 0x60;
//                   pSavedBondRec.addr[2] = 0x77;
//                   pSavedBondRec.addr[3] = 0x83;
//                   pSavedBondRec.addr[4] = 0x28;
//                   pSavedBondRec.addr[5] = 0xCC;

        pSavedBondRec.addr[5] = 0xF4;
        pSavedBondRec.addr[4] = 0x60;
        pSavedBondRec.addr[3] = 0x77;
        pSavedBondRec.addr[2] = 0x83;
        pSavedBondRec.addr[1] = 0x28;
        pSavedBondRec.addr[0] = 0xCC;

        pSavedBondRec.addrType = PEER_ADDRTYPE_RANDOM_OR_RANDOM_ID;
        pSavedBondRec.stateFlags = 0x1c;

        pPeerIRK[0] = 0x16;
        pPeerIRK[1] = 0x2B;
        pPeerIRK[2] = 0xF4;
        pPeerIRK[3] = 0x1B;
        pPeerIRK[4] = 0x23;
        pPeerIRK[5] = 0x15;
        pPeerIRK[6] = 0xC3;
        pPeerIRK[7] = 0xED;
        pPeerIRK[8] = 0xE2;
        pPeerIRK[9] = 0x08;
        pPeerIRK[10] = 0x7A;
        pPeerIRK[11] = 0xA5;
        pPeerIRK[12] = 0xF2;
        pPeerIRK[13] = 0x09;
        pPeerIRK[14] = 0x83;
        pPeerIRK[15] = 0xC5;
//                                        pPeerIRK[15]= 0x16;
//                                        pPeerIRK[14]= 0x2B;
//                                        pPeerIRK[13]= 0xF4;
//                                        pPeerIRK[12]= 0x1B;
//                                        pPeerIRK[11]= 0x23;
//                                        pPeerIRK[10]= 0x15;
//                                        pPeerIRK[9]= 0xC3;
//                                        pPeerIRK[8]= 0xED;
//                                        pPeerIRK[7]= 0xE2;
//                                        pPeerIRK[6]= 0x08;
//                                        pPeerIRK[5]= 0x7A;
//                                        pPeerIRK[4]= 0xA5;
//                                        pPeerIRK[3]= 0xF2;
//                                        pPeerIRK[2]= 0x09;
//                                        pPeerIRK[1]= 0x83;
//                                        pPeerIRK[0]= 0xC5;

        pLocalLtk.div = 0;
        pLocalLtk.keySize = 0x10;

        pPeerLtk.div = 0;
        pPeerLtk.keySize = 0x10;

        uint8_t i;
        for (i = 0; i < B_RANDOM_NUM_SIZE; i++)
        {
            pLocalLtk.rand[i] = 0;
            pPeerLtk.rand[i] = 0;
        }

        for (i = 0; i < KEYLEN; i++)
        {
            pPeerSRK[i] = 0;
            pPeerLtk.LTK[i] = 0xFF;
            pLocalLtk.LTK[i] = 0xFF;
        }

        pPeerSignCount = 0;
        charCfg.attrHandle = 0xffff;
        charCfg.value = 0xff;

        result_t = gapBondMgrImportBond(&pSavedBondRec, &pLocalLtk, &pPeerLtk,
                                        pPeerIRK, pPeerSRK, pPeerSignCount,
                                        &charCfg);

        if (result_t == SUCCESS)
        {
            Display_printf(dispHandle, 32, 0, "BOND IMPORT SUCCESS", NULL);
        }
        else
        {
            Display_printf(dispHandle, 32, 0, "BOND IMPORT FAIL", NULL);
        }


The hardcoded address and IRK are taken from a slightly modified simple peripheral example project where in the function SimplePeripheral_updateRPA, additionally the IRK is read out with the function GAP_GetIRK() as seen below.

static void SimplePeripheral_updateRPA(void)
{
  uint8_t* pRpaNew;
  uint8_t* pDevIDNew;
  uint8_t* pDevIRK;
  // Read the current RPA.
  pRpaNew = GAP_GetDevAddress(FALSE);
  pDevIDNew = GAP_GetDevAddress(TRUE);
  pDevIRK = GAP_GetIRK();

  if (memcmp(pRpaNew, rpa, B_ADDR_LEN))
  {
    // If the RPA has changed, update the display
    Display_printf(dispHandle, SP_ROW_RPA, 0, "RP Addr: %s",
                   Util_convertBdAddr2Str(pRpaNew));
    memcpy(rpa, pRpaNew, B_ADDR_LEN);

    Display_printf(dispHandle, SP_ROW_RPA + 5, 0, "ID Addr: %s",
                   Util_convertBdAddr2Str(pDevIDNew));
    Display_printf(dispHandle, SP_ROW_RPA + 6, 0, "IRK: %s",
                   Util_convertIKR2Str(pDevIRK));


  }
}

#define IRKLENGTH 16
char *Util_convertIKR2Str(uint8_t *pAddr)
{
  uint8_t     charCnt;
  char        hex[] = "0123456789ABCDEF";
  static char str[(2*IRKLENGTH)+3];
  char        *pStr = str;

  *pStr++ = '0';
  *pStr++ = 'x';

  // Start from end of addr
  pAddr += IRKLENGTH;

  for (charCnt = IRKLENGTH; charCnt > 0; charCnt--)
  {
    *pStr++ = hex[*--pAddr >> 4];
    *pStr++ = hex[*pAddr & 0x0F];
  }
#ifdef FREERTOS
  pStr = NULL;
#else
  *pStr = 0;
#endif
  return str;
}

This produces the following serial output:

 

The ID Addr and IRK are then hardcoded into the Bonding Import process of simple central device as seen above.

Unfortunately the central device cannot find any peripherals with the filter policy set as described above as seen below:

Where do you see potential issues with my approach? The issue should be very easily reproducible.

A few additional remarks:

  • The endianess of IRK and B_ADDR can be rule out as I tried out all combinations of big and little endian.
  • If I disable the filter policy the advertisment report can be found.
  • When I read out the previoulsly imported Bonding right after importing it as described in the BLE5 User guide as seen below I can see that the import was successful
      // Parameters needed for storing bonding information.
                            gapBondRec_t pSavedBondRec1;
                            gapBondLTK_t pLocalLtk1;
                            gapBondLTK_t pPeerLtk1;
                            uint8_t pPeerIRK1[KEYLEN];
                            uint8_t pPeerSRK1[KEYLEN];
                            uint32_t pPeerSignCount1;
                            gapBondCharCfg_t charCfg1;
    
                           uint8_t readStatus = FAILURE;
                           readStatus = gapBondMgrReadBondRec(PEER_ADDRTYPE_RANDOM_OR_RANDOM_ID,
                                                              pSavedBondRec.addr,
                                                              &pSavedBondRec1,
                                                              &pLocalLtk1,
                                                              &pPeerLtk1,
                                                              pPeerIRK1,
                                                              pPeerSRK1,
                                                              pPeerSignCount1,
                                                              &charCfg1);
                           if (readStatus == SUCCESS)
                           {
                             // If read success, then export the data
                             // Here we will print it out for later use.
                             // For the print, we added the following defines
                             // Please consider your own example and modify as needed
                              #define SP_ROW_DEBUG_BondLog  (TBM_ROW_APP + 9)
                              #define SP_ROW_DEBUG_PeerAddr (TBM_ROW_APP + 10)
                              #define SP_ROW_DEBUG_LocalLTK (TBM_ROW_APP + 16)
                              #define SP_ROW_DEBUG_PeerIRK  (TBM_ROW_APP + 40)
                              #define SP_ROW_DEBUG_PeerSRK  (TBM_ROW_APP + 56)
    
                             Display_printf(dispHandle, SP_ROW_DEBUG_PeerAddr, 0,
                                            "Peer Device Addr = [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x];",
                                           pSavedBondRec1.addr[0],
                                           pSavedBondRec1.addr[1],
                                           pSavedBondRec1.addr[2],
                                           pSavedBondRec1.addr[3],
                                           pSavedBondRec1.addr[4],
                                           pSavedBondRec1.addr[5]);
    
                             Display_printf(dispHandle, SP_ROW_DEBUG_PeerAddr+1, 0, "Peer Device AddrType = 0x%02x; stateFlag = 0x%02x;",pSavedBondRec1.addrType,pSavedBondRec1.stateFlags);
                             Display_printf(dispHandle, SP_ROW_DEBUG_PeerAddr+2, 0, "Local Device eDiv = 0x%02x; keySize = 0x%02x", pLocalLtk1.div, pLocalLtk1.keySize);
                             Display_printf(dispHandle, SP_ROW_DEBUG_PeerAddr+3, 0, "peer Device SignCount = 0x%08x;", pPeerSignCount1);
                             for (i = 0; i < KEYLEN; i++)
                             {
                                 Display_printf(dispHandle, SP_ROW_DEBUG_LocalLTK+i, 0, "Local Device LTK[%d]= 0x%02x;", i, pLocalLtk1.LTK[i]);
                                 Display_printf(dispHandle, SP_ROW_DEBUG_PeerIRK+i, 0, "Peer Device IRK[%d]= 0x%02x;", i, pPeerIRK1[i]);
                                 Display_printf(dispHandle, SP_ROW_DEBUG_PeerSRK+i, 0, "Peer Device SRK[%d]= 0x%02x;", i, pPeerSRK1[i]);
                             }
                             for (i = 0; i < B_RANDOM_NUM_SIZE; i++)
                             {
                                 Display_printf(dispHandle, SP_ROW_DEBUG_LocalLTK+16+i, 0, "Local Device rand[%d]= 0x%02x;", i, pLocalLtk1.rand[i]);
                             }
    
                             Display_printf(dispHandle, SP_ROW_DEBUG_PeerSRK+16+1, 0, "Charcfg attrHandle = 0x%04x; value = 0x%02x", charCfg1.attrHandle, charCfg1.value);
                           }
    

Thank you very much for your support!

  • Hi, 

    Can you manually add the device into resolving/white list using the following APIs to see if that makes any difference?

    HCI_LE_AddDeviceToResolvingListCmd

    HCI_LE_AddWhiteListCmd

  • Hi Christin, 

    thank you for your quick response.

    With the manual method, I could successfully get the simple central and peripheral example to resolve and filter the address. I can add the peripherals IRK and ID Address with the following code: 

    static void import_bonding_manual(void)
    {
    
        uint8_t peerIdAddr[B_ADDR_LEN];
        uint8_t pPeerIRK[KEYLEN];
        uint8_t peerIdAddrType = HCI_RANDOM_DEVICE_ADDRESS;
    
        uint8_t *pDevIRK;
        pDevIRK = GAP_GetIRK(NULL);
    
        peerIdAddr[0] = 0xCC;
        peerIdAddr[1] = 0x28;
        peerIdAddr[2] = 0x83;
        peerIdAddr[3] = 0x77;
        peerIdAddr[4] = 0x60;
        peerIdAddr[5] = 0xF4;
    
        pPeerIRK[0] = 0xC5;
        pPeerIRK[1] = 0x83;
        pPeerIRK[2] = 0x09;
        pPeerIRK[3] = 0xF2;
        pPeerIRK[4] = 0xA5;
        pPeerIRK[5] = 0x7A;
        pPeerIRK[6] = 0x08;
        pPeerIRK[7] = 0xE2;
        pPeerIRK[8] = 0xED;
        pPeerIRK[9] = 0xC3;
        pPeerIRK[10] = 0x15;
        pPeerIRK[11] = 0x23;
        pPeerIRK[12] = 0x1B;
        pPeerIRK[13] = 0xF4;
        pPeerIRK[14] = 0x2B;
        pPeerIRK[15] = 0x16;
    
        HCI_LE_AddDeviceToResolvingListCmd(peerIdAddrType, peerIdAddr, pPeerIRK,
                                           pDevIRK);
    
        HCI_LE_AddWhiteListCmd(peerIdAddrType, peerIdAddr);
    
    }

    An set the filter policy like this:

          uint8_t result_t;
          temp8 = SCAN_FLT_POLICY_WL;
          result_t = GapScan_setParam(SCAN_PARAM_FLT_POLICY, &temp8);

    This method also works with my original setup where I wanted to substitute the central device. 

    However this is only good for address resolution and helps figuring out the endianess of the address and keys. 

    I still can't import a bond into the GapBondMgr in either of the two setups.

    For the simple central and simple peripheral setup no LTKs exist. Adding a generic LTK should not break the functionality of the resolving and white list though. Here is the simple central code:

    void import_bonding_BndMgr(void)
    {
    
        uint8_t result_t;
        uint8_t sync_WL = TRUE;
        result_t = GAPBondMgr_SetParameter(GAPBOND_AUTO_SYNC_WL, sizeof(uint8_t),
                                           &sync_WL);
    
        if (result_t == SUCCESS)
        {
            Display_printf(dispHandle, 31, 0, "GAPBOND_AUTO_SYNC_WL SET SUCCESS",
                           NULL);
        }
        else
        {
            Display_printf(dispHandle, 31, 0, "GAPBOND_AUTO_SYNC_WL SET FAIL",
            NULL);
        }
    
        // Import Bonding
        // Parameters needed for storing bonding information.
        gapBondRec_t pSavedBondRec;
        gapBondLTK_t pLocalLtk;
        gapBondLTK_t pPeerLtk;
        uint8_t pPeerIRK[KEYLEN];
        uint8_t pPeerSRK[KEYLEN];
        uint32_t pPeerSignCount;
        gapBondCharCfg_t charCfg;
    
        pSavedBondRec.addr[0] = 0xCC;
        pSavedBondRec.addr[1] = 0x28;
        pSavedBondRec.addr[2] = 0x83;
        pSavedBondRec.addr[3] = 0x77;
        pSavedBondRec.addr[4] = 0x60;
        pSavedBondRec.addr[5] = 0xF4;
    
        pSavedBondRec.addrType = PEER_ADDRTYPE_RANDOM_OR_RANDOM_ID;
        pSavedBondRec.stateFlags = 0x1c;
    
        pPeerIRK[0] = 0xC5;
        pPeerIRK[1] = 0x83;
        pPeerIRK[2] = 0x09;
        pPeerIRK[3] = 0xF2;
        pPeerIRK[4] = 0xA5;
        pPeerIRK[5] = 0x7A;
        pPeerIRK[6] = 0x08;
        pPeerIRK[7] = 0xE2;
        pPeerIRK[8] = 0xED;
        pPeerIRK[9] = 0xC3;
        pPeerIRK[10] = 0x15;
        pPeerIRK[11] = 0x23;
        pPeerIRK[12] = 0x1B;
        pPeerIRK[13] = 0xF4;
        pPeerIRK[14] = 0x2B;
        pPeerIRK[15] = 0x16;
    
        pLocalLtk.div = 0;
        pLocalLtk.keySize = 0x10;
    
        pPeerLtk.div = 0;
        pPeerLtk.keySize = 0x10;
    
        uint8_t i;
        for (i = 0; i < B_RANDOM_NUM_SIZE; i++)
        {
            pLocalLtk.rand[i] = 0;
            pPeerLtk.rand[i] = 0;
        }
    
        for (i = 0; i < KEYLEN; i++)
        {
            pPeerSRK[i] = 0;
            pPeerLtk.LTK[i] = 0xFF;
            pLocalLtk.LTK[i] = 0xFF;
        }
    
        pPeerSignCount = 0;
        charCfg.attrHandle = 0xffff;
        charCfg.value = 0xff;
    
        result_t = gapBondMgrImportBond(&pSavedBondRec, &pLocalLtk, &pPeerLtk,
                                        pPeerIRK, pPeerSRK, pPeerSignCount,
                                        &charCfg);
    
        if (result_t == SUCCESS)
        {
            Display_printf(dispHandle, 32, 0, "BOND IMPORT SUCCESS", NULL);
        }
        else
        {
            Display_printf(dispHandle, 32, 0, "BOND IMPORT FAIL", NULL);
        }
    
    
    }

    Also, from the documentation I am not sure what the parameters pSavedBondRec.stateFlags, pLocalLtk.div, pLocalLtk.rand, pPeerLtk.rand, pPeerSRK, pPeerSignCount, charCfg.attrHandle, charCfg.value should be set to.

    Can/How do they influence the behavior? 

    Thank you!

  • Hi Felix

    Which SDK are you based on? Here I see there is only IRK involved,  no LTK shown. So does LTK exist in your system? IRK is just for resolving the RPA, bondmgr is more relates to bonding/pairing. I see now you can manually add IRK and device to whitelist and resolve the device. Can you please help to explain more about your further needs?

    Thanks.

    Best Regards,

    Barbara Wu 

  • Thank you Barbara, I will come back to you on this topic later! For now the manual workaround works for me, but still does not solve the issue.

  • Hi , Hi

    I now face difficulties with the manual method and my simple_peripheral simple_central setup. For this I opened a new thread: https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1134515/launchxl-cc26x2r1-let-simple_central-resolve-and-filter-simple_peripheral-advertisements-rpa-irk-privacy.

    It would be very kind if you could help me resolve this issue, then I can work on the Bonding issue from above.

    Best regards

    Felix