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.

CC2530: what's default behaviour if ZR/ZED received Tranport Key(TCLK) without Request Key?

Part Number: CC2530
Other Parts Discussed in Thread: Z-STACK

Hi Ryan Brown1 & YK,

 It's been a long time,I'm sorry to interrupt,we encounter a strange behaviour on z-stack 3.0.2 with CC2530,that caused our devices(ZR) loss zigbee network(seems like Leave but not received any Leave Request) in next power cycle,as well as known,z-stack 3.0.2 was very stable until now at least 3+ years even if not update,so we don't think the stack have some bug.

So we have to research the BDB specification documents to attemp find some fact. BDB specification from zigbee alliance

"10.2.6 Receiving new Link Keys" form BDB doc describe the behaviour if node receives a Transport Key contain a TCLK, but have not sent a Request Key, it shall ignore the message,and variable  acceptNewUnsolicitedTrustCenterLinkKey
 seems like find in ZDSecMgr.c source file but was comment, so we don't know the behavious in z-stack.

attachments is our ota capture with ubiqua,0xE46C and 0xA1D7 loss the zigbee network information in next power cycle.

thanks very much.

0xE46C and 0xA1D7 loss network information.zip

  • Hi behold,

    Thank you for sharing this section of the BDB Spec.  It appears to be a condition which does not exist in the Z-Stack solution, either in the Z-Stack 3.0.2 or SimpleLink SDK.  It was most likely missed because it is not covered in any test cases and not relevant for platform certification.  At any rate it should definitely be addressed and I have informed the Software Development Team so that they can implement a solution accordingly.   Although there is no specific acceptNewTrustCenterLinkKey boolean value in the Z-Stack code, I recommend that you add it to ZDSecMgr.c which is initialized to FALSE and turned to true during bdb_requestTCLinkKey from bdb.c, then checked and reset inside ZDSecMgrTransportKeyInd.

    Regards,
    Ryan

  • I will paste my changes in z-stack,this may be help more engineer.

    bdb.c

    extern bool acceptNewUnsolicitedApplicationLinkKey;
    
    
    
    
    /*********************************************************************
     * @fn      bdb_ProcessNodeDescRsp
     *
     * @brief   Process Node Descriptor response to validate the stack version of the
     *
     * @param   zdoIncomingMsg_t *pMsg
     *
     * @return  none
     */
    void bdb_ProcessNodeDescRsp(zdoIncomingMsg_t *pMsg)
    {
      //Avoid processing unintended messages
      if(requestNewTrustCenterLinkKey && 
        (bdbCommissioningProcedureState.bdbCommissioningState == BDB_COMMISSIONING_STATE_TC_LINK_KEY_EXCHANGE))
      {
        if(!APSME_IsDistributedSecurity())
        {
          //Is this from the coordinator?
          if(pMsg->srcAddr.addr.shortAddr == 0x0000)
          {
            ZDO_NodeDescRsp_t NDRsp;
            uint8 StackComplianceRev;
    
            //Stop timer to avoid unintended resets
            osal_stop_timerEx( bdb_TaskID, BDB_PROCESS_TIMEOUT);
            
            ZDO_ParseNodeDescRsp(pMsg, &NDRsp);
            
            StackComplianceRev = NDRsp.nodeDesc.ServerMask >> STACK_COMPLIANCE_CURRENT_REV_POS;
            
            if( StackComplianceRev >= STACK_COMPL_REV_21 )
            {
              acceptNewUnsolicitedApplicationLinkKey = TRUE;
              bdb_tcLinkKeyExchangeAttempt(TRUE,BDB_REQ_TC_LINK_KEY);
            }
            else
            {
              APSME_TCLKDevEntry_t TCLKDevEntry;
              
              //Save the KeyAttribute for joining device that it has joined non-R21 nwk
              TCLKDevEntry.keyAttributes = ZG_NON_R21_NWK_JOINED;
              osal_nv_write(ZCD_NV_TCLK_TABLE_START,osal_offsetof(APSME_TCLKDevEntry_t,keyAttributes),sizeof(uint8),&TCLKDevEntry.keyAttributes);
              
              bdb_setNodeJoinLinkKeyType(BDB_DEFAULT_GLOBAL_TRUST_CENTER_LINK_KEY);
              bdb_reportCommissioningState(BDB_COMMISSIONING_STATE_TC_LINK_KEY_EXCHANGE, TRUE);
            }
          }
        }
      }
    }

    ZDSecMgr.c

    bool acceptNewUnsolicitedApplicationLinkKey = FALSE;
    
    
    
    /******************************************************************************
     * @fn          ZDSecMgrTransportKeyInd
     *
     * @brief       Process the ZDO_TransportKeyInd_t message.
     *
     * @param       ind - [in] ZDO_TransportKeyInd_t indication
     *
     * @return      none
     */
    void ZDSecMgrTransportKeyInd( ZDO_TransportKeyInd_t* ind )
    {
      uint8 index;
      uint8 zgPreConfigKey[SEC_KEY_LEN];
    
      ZDSecMgrUpdateTCAddress( ind->srcExtAddr );
      
    #if ZG_BUILD_JOINING_TYPE
      if(ZG_DEVICE_JOINING_TYPE)
      {
        //Update the TC address in the entry
        osal_nv_write(ZCD_NV_TCLK_TABLE_START, osal_offsetof(APSME_TCLKDevEntry_t,extAddr), Z_EXTADDR_LEN, ind->srcExtAddr);
      }
    #endif
      
      // check for distributed security
      if ( ( ZG_BUILD_RTR_TYPE ) && osal_isbufset( ind->srcExtAddr, 0xFF, Z_EXTADDR_LEN ) )
      {
        ZDSecMgrPermitJoiningEnabled = TRUE;  
      }
      
      // load Trust Center data if needed
      ZDSecMgrTCDataLoad( ind->srcExtAddr );
      
      if ( ( ind->keyType == KEY_TYPE_NWK ) ||
           ( ind->keyType == 6            ) )
      {
        // check for dummy NWK key (all zeros)
        for ( index = 0;
              ( (index < SEC_KEY_LEN) && (ind->key[index] == 0) );
              index++ );
    
        if ( index == SEC_KEY_LEN )
        {
          // load preconfigured key - once!!
          if ( !_NIB.nwkKeyLoaded )
          {
            ZDSecMgrReadKeyFromNv(ZCD_NV_PRECFGKEY, zgPreConfigKey);
            SSP_UpdateNwkKey( zgPreConfigKey, 0 );
            SSP_SwitchNwkKey( 0 );
    
            // clear local copy of key
            osal_memset(zgPreConfigKey, 0x00, SEC_KEY_LEN);
          }
        }
        else
        {
          SSP_UpdateNwkKey( ind->key, ind->keySeqNum );
          if ( !_NIB.nwkKeyLoaded )
          {
            SSP_SwitchNwkKey( ind->keySeqNum );
          }
        }
    
        // handle next step in authentication process
        ZDSecMgrAuthNwkKey();
      }
      else if ( ind->keyType == KEY_TYPE_TC_LINK )
      {
        uint16 entryIndex;
        uint8 found;
        APSME_TCLKDevEntry_t TCLKDevEntry;
        
        // according to BDB specification (https://zigbeealliance.org/wp-content/uploads/2019/12/docs-13-0402-13-00zi-Base-Device-Behavior-Specification-2-1.pdf)
        // chapter "10.2.6 Receiving new Link Keys"
        // node has not sent a request for one and acceptNewUnsolicitedTrustCenterLinkKey is set to FALSE,we SHALL ignore the message
        if(acceptNewUnsolicitedApplicationLinkKey == TRUE)
        {
          //Search the entry, which should exist at this point
          entryIndex = APSME_SearchTCLinkKeyEntry(ind->srcExtAddr, &found, &TCLKDevEntry);
    
          if(found)
          {
            //If the key was an IC, then erase the entry since that will not longer be used.
            if(TCLKDevEntry.keyAttributes == ZG_PROVISIONAL_KEY)
            {
              APSME_EraseICEntry(&TCLKDevEntry.SeedShift_IcIndex);
            }
            
            TCLKDevEntry.keyAttributes = ZG_UNVERIFIED_KEY;
            TCLKDevEntry.keyType = ZG_UNIQUE_LINK_KEY;
            TCLKDevEntry.rxFrmCntr = 0;
            TCLKDevEntry.txFrmCntr = 0;
            TCLKDevEntry.SeedShift_IcIndex = 0;
            
            //Update the entry
            osal_nv_write(entryIndex,0,sizeof(APSME_TCLKDevEntry_t),&TCLKDevEntry);
    
            //Create the entry for the key
            if(ZSUCCESS == osal_nv_item_init(ZCD_NV_TCLK_JOIN_DEV,SEC_KEY_LEN,ind->key) )
            {
              //Or replace it if already existed
              osal_nv_write(ZCD_NV_TCLK_JOIN_DEV,0,SEC_KEY_LEN,ind->key);
            }
            
            acceptNewUnsolicitedApplicationLinkKey = FALSE;
            bdb_tcLinkKeyExchangeAttempt(TRUE,BDB_REQ_VERIFY_TC_LINK_KEY);
          }
        }
      }
      else if ( ind->keyType == KEY_TYPE_APP_LINK )
      {
        if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD )
        {
          uint16           ami;
          ZDSecMgrEntry_t* entry;
    
          // get the address index
          if ( ZDSecMgrExtAddrLookup( ind->srcExtAddr, &ami ) != ZSuccess )
          {
            // store new EXT address
            ZDSecMgrAddrStore( INVALID_NODE_ADDR, ind->srcExtAddr, &ami );
            ZDP_NwkAddrReq( ind->srcExtAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
          }
    
          ZDSecMgrEntryLookupAMI( ami, &entry );
    
          if ( entry == NULL )
          {
            // get new entry
            if ( ZDSecMgrEntryNew( &entry ) == ZSuccess )
            {
              // finish setting up entry
              entry->ami = ami;
            }
          }
    
          ZDSecMgrLinkKeySet( ind->srcExtAddr, ind->key );
    
    #if defined NV_RESTORE
          ZDSecMgrWriteNV();  // Write the control record for the new established link key to NV.
    #endif
        }
      }
    }

  • Thanks for sharing this.