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.

I found a danger in z-stack when coordinate sever "end-device-bind" for more than tow device(both router and end-device)

Other Parts Discussed in Thread: Z-STACK

Function "ZDO_MatchEndDeviceBind" in source file "ZDObject.c" which can be only processed by coordinate has a danger. When the coordinate receives 2 ZDP “end-device-bind-req” command,and the “end-device-bind-req” commands request more than 2 or more cluster-ID binding.The coordinate will allocate buffer for “matchED” and store binding cluster in it, and run "end-device-bind" service in function "ZDMatchSendState".At this moment,if a new ZDP "end-device-bind-req" command is received by coordinate,the buffer pointer “matchED” 's member "ed2" will allocate new memory space for the new command.But the "ed2" has allocated space for last command and its space will not be free until the "end-device-bind" service is finished.So the memory sapce (Heap) of coordinate has allocated for some one but will not be free,that will make coordinate down.

  • To deal with it,"ZDO_MatchEndDeviceBind" can be fixed like this:


    void ZDO_MatchEndDeviceBind( ZDEndDeviceBind_t *bindReq )
    {
    zAddrType_t dstAddr;
    uint8 sendRsp = FALSE;
    uint8 status;

    // Is this the first request?
    if ( matchED == NULL )
    {
    // Create match info structure
    matchED = (ZDMatchEndDeviceBind_t *)osal_mem_alloc( sizeof ( ZDMatchEndDeviceBind_t ) );
    if ( matchED )
    {
    // Clear the structure
    osal_memset( (uint8 *)matchED, 0, sizeof ( ZDMatchEndDeviceBind_t ) );

    // Copy the first request's information
    if ( !ZDO_CopyMatchInfo( &(matchED->ed1), bindReq ) )
    {
    status = ZDP_NO_ENTRY;
    sendRsp = TRUE;
    }
    }
    else
    {
    status = ZDP_NO_ENTRY;
    sendRsp = TRUE;
    }

    if ( !sendRsp )
    {
    // Set into the correct state
    matchED->state = ZDMATCH_WAIT_REQ;

    // Setup the timeout
    APS_SetEndDeviceBindTimeout( AIB_MaxBindingTime, ZDO_EndDeviceBindMatchTimeoutCB );
    }
    }
    else
    {
    if(matchED->state == ZDMATCH_WAIT_REQ)//when bind is running,refuse new end-device-bind-req
    {
    matchED->state = ZDMATCH_SENDING_BINDS;

    // Copy the 2nd request's information
    if ( !ZDO_CopyMatchInfo( &(matchED->ed2), bindReq ) )
    {
    status = ZDP_NO_ENTRY;
    sendRsp = TRUE;
    }

    // Make a source match for ed1
    matchED->ed1numMatched = ZDO_CompareClusterLists(
    matchED->ed1.numOutClusters, matchED->ed1.outClusters,
    matchED->ed2.numInClusters, matchED->ed2.inClusters, ZDOBuildBuf );
    if ( matchED->ed1numMatched )
    {
    // Save the match list
    matchED->ed1Matched = osal_mem_alloc( (short)(matchED->ed1numMatched * sizeof ( uint16 )) );
    if ( matchED->ed1Matched )
    {
    osal_memcpy( matchED->ed1Matched, ZDOBuildBuf, (matchED->ed1numMatched * sizeof ( uint16 )) );
    }
    else
    {
    // Allocation error, stop
    status = ZDP_NO_ENTRY;
    sendRsp = TRUE;
    }
    }

    // Make a source match for ed2
    matchED->ed2numMatched = ZDO_CompareClusterLists(
    matchED->ed2.numOutClusters, matchED->ed2.outClusters,
    matchED->ed1.numInClusters, matchED->ed1.inClusters, ZDOBuildBuf );
    if ( matchED->ed2numMatched )
    {
    // Save the match list
    matchED->ed2Matched = osal_mem_alloc( (short)(matchED->ed2numMatched * sizeof ( uint16 )) );
    if ( matchED->ed2Matched )
    {
    osal_memcpy( matchED->ed2Matched, ZDOBuildBuf, (matchED->ed2numMatched * sizeof ( uint16 )) );
    }
    else
    {
    // Allocation error, stop
    status = ZDP_NO_ENTRY;
    sendRsp = TRUE;
    }
    }

    if ( (sendRsp == FALSE) && (matchED->ed1numMatched || matchED->ed2numMatched) )
    {
    // Do the first unbind/bind state
    ZDMatchSendState( ZDMATCH_REASON_START, ZDP_SUCCESS, 0 );
    }
    else
    {
    status = ZDP_NO_MATCH;
    sendRsp = TRUE;
    }
    }
    //refuse new request when end device bind is busy
    else
    {
    status = ZDP_NO_ENTRY;
    dstAddr.addrMode = Addr16Bit;
    dstAddr.addr.shortAddr = bindReq->srcAddr;
    ZDP_EndDeviceBindRsp( bindReq->TransSeq, &dstAddr, status, bindReq->SecurityUse );
    return;
    }
    }

    if ( sendRsp )
    {
    // send response to this requester
    dstAddr.addrMode = Addr16Bit;
    dstAddr.addr.shortAddr = bindReq->srcAddr;
    ZDP_EndDeviceBindRsp( bindReq->TransSeq, &dstAddr, status, bindReq->SecurityUse );

    if ( matchED->state == ZDMATCH_SENDING_BINDS )
    {
    // send response to first requester
    dstAddr.addrMode = Addr16Bit;
    dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
    ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, status, matchED->ed1.SecurityUse );
    }

    // Process ended - release memory used
    ZDO_RemoveMatchMemory();
    }
    }
  • Thank you for bringing this up Aries, I will further investigate and file a bug with our Software Team if necessary. Can you state which device and Z-Stack version, and example project you've tested this on? Have you already referenced the following Wiki page? processors.wiki.ti.com/.../Zigbee_Known_Issues_and_Proposed_Fixes

    Thanks,
    Ryan
  • Both z-stack 3.0.1 and z-stack for CC26x2 have this bug, and this bug is appearing at every z-stack verison.
  • Thank you once more for the information Aries, the software developers have been notified and are working towards a solution. If you have any further information or workarounds please feel free to contact me in a private message.

    Regards,
    Ryan