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.

Pairing fails with SMP_PAIRING_FAILED_CONFIRM_VALUE (0x04)

Other Parts Discussed in Thread: CC2540, CC2541

I have two scenarios for pairing devices, a instant pairing and pairing prompt that delays. The instant works correctly, but the delay does not. I see the same data being passed into:

static void gapBondMgrAuthenticate( uint16 connHandle, uint8 addrType, gapPairingReq_t *pPairReq )

but I see in the Packet Sniffer:

The Working one has the same values in the SM_Pairing_Req and SP_Pairing_Rsp for both KeyDist feilds (0x07). The Failing one does not (0x07 & 0x00).

It looks like those values should come from the keyDist object, but that is always filled with 1's. So I'm not sure how the (0x07) is generated. 

  • I tried forcing the values and it still fail's:

    static void gapBondMgrAuthenticate( uint16 connHandle, uint8 addrType,
                                        gapPairingReq_t *pPairReq )
    {
      gapAuthParams_t params;
    
      VOID osal_memset( &params, 0, sizeof ( gapAuthParams_t ) );
    
      // Setup the pairing parameters
      params.connectionHandle = connHandle;
      params.secReqs.ioCaps = gapBond_IOCap;
      params.secReqs.oobAvailable = gapBond_OOBDataFlag;
      params.secReqs.maxEncKeySize = gapBond_KeySize;
    
    //  params.secReqs.keyDist.sEncKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_SENCKEY) ? TRUE : FALSE;
    //  params.secReqs.keyDist.sIdKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_SIDKEY) ? TRUE : FALSE;
    //  params.secReqs.keyDist.mEncKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_MENCKEY) ? TRUE : FALSE;
    //  params.secReqs.keyDist.mIdKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_MIDKEY) ? TRUE : FALSE;
    //  params.secReqs.keyDist.mSign = (gapBond_KeyDistList & GAPBOND_KEYDIST_MSIGN) ? TRUE : FALSE;
    //  params.secReqs.keyDist.sSign = (gapBond_KeyDistList & GAPBOND_KEYDIST_SSIGN) ? TRUE : FALSE;
    //  
      params.secReqs.keyDist.sEncKey = 1;
      params.secReqs.keyDist.sIdKey = 1;
      params.secReqs.keyDist.mEncKey = 1;
      params.secReqs.keyDist.mIdKey = 1;
      params.secReqs.keyDist.mSign = 1;
      params.secReqs.keyDist.sSign = 1;
      pPairReq->keyDist.mEncKey = 1;
      pPairReq->keyDist.mIdKey = 1;
      pPairReq->keyDist.mSign = 1;
      pPairReq->keyDist.sEncKey = 1;
      pPairReq->keyDist.sIdKey = 1;
      pPairReq->keyDist.sSign = 1;
    
      // Is bond manager setup for OOB data?
      if ( gapBond_OOBDataFlag )
      {
        VOID osal_memcpy( params.secReqs.oob, gapBond_OOBData, KEYLEN );
      }
    
      if ( gapBond_Bonding && addrType != ADDRTYPE_PUBLIC )
      {
        // Force a slave ID key
        params.secReqs.keyDist.sIdKey = TRUE;
      }
    
      params.secReqs.authReq |= (gapBond_Bonding) ? SM_AUTH_STATE_BONDING : 0;
      params.secReqs.authReq |= (gapBond_MITM) ? SM_AUTH_STATE_AUTHENTICATED : 0;
    
      VOID GAP_Authenticate( &params, pPairReq );
    }

  • Hi Josh,

    Can you provide details on how you are doing "pairing prompt that delays"? Also, what is the other device? Another CC2540 or smartphone, etc.?

    Best wishes
  • One device is a cc2540 the other is a cc2541.

    All I am doing is Saving the Pairing Detail on a GAP_PAIRING_REQ_EVENT:

    gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg;
    pPairReqVal = pPkt;

    then the user can trigger it to respond later:

    linkDBItem_t *pLinkItem = linkDB_Find( pPairReqVal->connectionHandle);
    gapBondMgrAuthenticate( pPairReqVal->connectionHandle, pLinkItem->addrType, &(pPairReqVal->pairReq) );

  • Hi Josh,

    I'm not sure what's going on. Can you provide a patch showing the condition with the delay?

    Best wishes
  •     case GAP_PAIRING_REQ_EVENT:
          {
            gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg;
    
            if ( gapBond_AutoFail != FALSE )
            {
              // Auto Fail TEST MODE (DON'T USE THIS) - Sends pre-setup reason
              VOID GAP_TerminateAuth( pPkt->connectionHandle, gapBond_AutoFailReason );
            }
            else if ( gapBond_PairingMode == GAPBOND_PAIRING_MODE_NO_PAIRING )
            {
              // No Pairing - Send error
              VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED );
            }
            else
            {
              linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
    
              // Requesting bonding?
              if ( pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING )
              {
                if ( pLinkItem )
                {
                  if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPkt->pairReq.keyDist.mIdKey == FALSE) )
                  {
                    uint8 publicAddr[B_ADDR_LEN];
    
                    // Check if we already have the public address in NV
                    if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE )
                    {
                      // Can't bond to a non-public address if we don't know the public address
                      VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ );
                      break;
                    }
                  }
                }
                else
                {
                  // Can't find the connection, ignore the message
                  break;
                }
              }
              if ( gapBond_PairingMode == GAPBOND_PAIRING_MODE_WAIT_FOR_REQ && !initiate_pair ){
                pPairReqVal = pPkt;
                // Call app state callback
                if ( pGapBondCB && pGapBondCB->pairStateCB )
                {
                  pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_REQUEST, SUCCESS );
                }
              }else{
                // Send pairing response
                gapBondMgrAuthenticate( pPkt->connectionHandle, pLinkItem->addrType, &(pPkt->pairReq) );
                // Call app state callback
                if ( pGapBondCB && pGapBondCB->pairStateCB )
                {
                  pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_STARTED, SUCCESS );
                }
              }
            }
          }
          break;

    Then to trigger the response:

    void GAPBondMgr_RequestResond( uint8 accept, uint16 connHandle, uint8 role )
    {
      linkDBItem_t *pLinkItem = linkDB_Find( connHandle );
          if(pPairReqVal != NULL){
            // Requesting bonding?
            uint8 finish = TRUE;
            if ( pPairReqVal->pairReq.authReq & SM_AUTH_STATE_BONDING )
            {
              if ( pLinkItem )
              {
                if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPairReqVal->pairReq.keyDist.mIdKey == FALSE) )
                {
                  uint8 publicAddr[B_ADDR_LEN];
    
                  // Check if we already have the public address in NV
                  if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE )
                  {
                    // Can't bond to a non-public address if we don't know the public address
                    VOID GAP_TerminateAuth( pPairReqVal->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ );
                    finish = FALSE;
                  }
                }
              }
              else
              {
                // Can't find the connection, ignore the message
                finish = FALSE;
              }
            }
            // Send pairing response
            if(finish){
              gapBondMgrAuthenticate( pPairReqVal->connectionHandle, pLinkItem->addrType, &(pPairReqVal->pairReq) );
        }
      }else{
        VOID GAP_TerminateAuth( connHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );
      }
    }