zbSize_t Mgmt_Direct_Join_req
(
  zbMgmtDirectJoinRequest_t *pMsgComingIn
)
{
  zdoNlmeMessage_t  *pZdoNlmeMsg;

#if ((gStandardSecurity_d || gHighSecurity_d) && gApsMaxEntriesForPermissionsTable_c)
  nlmeZdoMessage_t zdoMsg;
#endif

#if ((gStandardSecurity_d || gHighSecurity_d) && gApsMaxEntriesForPermissionsTable_c)
  if (!CommandHasPermission(NlmeGetRequest(gNwkShortAddress_c), gNetworkSettingsPermission_c))
  {
    zdoMsg.msgData.directJoinConf.status = gZdpNotAuthorized_c;
    Zdp_Mgmt_Direct_Join_conf((void *)&zdoMsg);
    return 0;
  }
#endif

  pZdoNlmeMsg = MSG_Alloc(MbrSizeof(zdoNlmeMessage_t, msgType) + sizeof(nlmeDirectJoinReq_t));

  if (pZdoNlmeMsg)
  {
    pZdoNlmeMsg->msgType = gNlmeDirectJoinRequest_c;

    FLib_MemCpy(&pZdoNlmeMsg->msgData.directJoinReq, pMsgComingIn, sizeof(nlmeDirectJoinReq_t));

    ZDO_SendEvent(gZdoEvent_ManagementCommand_c);

    (void)ZDO_NLME_SapHandler((void *)pZdoNlmeMsg);
  }

  return 0;
}
/*-------------------- Mgmt_Permit_Joining_req  --------------------

	IN: The package with the request information.

	OUT: The size in bytes of the request payload.
*/
zbSize_t Mgmt_Permit_Joining_req
(
zbMgmtPermitJoiningRequest_t *pMessageComingIn, /*IN The package with the request information.  */
zbNwkAddr_t aDestAddr /* IN: The destination address where to send the request.  */
)
{
zdoNlmeMessage_t * pZdoNlmeMsg;

  /* If the destiantion address is to all awake devices, first turn it on locally and then send it OTA. */
  if(FLib_MemCmp((uint8_t *)gaBroadcastZCnZR, aDestAddr, sizeof(zbNwkAddr_t)))
  {
    /* Do the permit joinig locally as well. */
    pZdoNlmeMsg = MSG_AllocType(zdoNlmeMessage_t);

    /* If we can not set this locally is highly probably that we are not able to send packets OTA. */
    if(pZdoNlmeMsg == NULL)
      return 0;
    if (NlmeGetRequest(gDevType_c) != gEndDevice_c)
    {          
      /* Build the NLME request using the incoming info. */
      BeeUtilZeroMemory(pZdoNlmeMsg,sizeof(zdoNlmeMessage_t ));
      pZdoNlmeMsg->msgData.permitJoiningReq.permitDuration = pMessageComingIn->PermitDuration;
      pZdoNlmeMsg->msgType = gNlmePermitJoiningRequest_c;
      (void)ZDO_NLME_SapHandler(pZdoNlmeMsg);
    }
  }

  /* By returning the size ZDP send out the request. */
  return sizeof(zbMgmtPermitJoiningRequest_t);
}
void ZDO_StartLinkStatus(){
  
  /* Jitter time to avoid synchronization with link status of others devices.
   Time in milliseconds. */
  uint8_t gNwkLinkStatusJitterInterval = GetRandomRange(0,10);
  
  /* Start the timer */
  TMR_StartSingleShotTimer(gLinkStatusTimerID,
                           (TmrSeconds( NlmeGetRequest(gNwkLinkStatusPeriod_c) ) + gNwkLinkStatusJitterInterval),
                           CustomLinkStatusTimeOutCallBack);

}
/*
  This funciton only helps to hold the saving common code into one place instead of repeating
  it for each switch case on the function ZdoNwkMng_SaveToNvm.
*/
void ZdoNwkMng_SaveDataSet(NvDataSetID_t  dataSetId)
{
#if gEndDevCapability_d || gComboDeviceCapability_d
#if gComboDeviceCapability_d
  if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
#endif
    (void)NvSaveOnIdle(dataSetId);
#if gComboDeviceCapability_d
  else
    (void)NvSaveOnInterval(dataSetId);
#endif
#else
  (void)NvSaveOnInterval(dataSetId);
#endif
}
Exemple #5
0
void OnOffLight_AppSetLightState
  (
  zbEndPoint_t endPoint,    /* IN: APP endpoint */
  zclCmd_t command          /* IN: */
  )
{
  zclOnOffReq_t req;

  /* set up address info for a unicast to ourselves */
  req.addrInfo.dstAddrMode = gZbAddrMode16Bit_c;
  Copy2Bytes(req.addrInfo.dstAddr.aNwkAddr, NlmeGetRequest(gNwkShortAddress_c));
  req.addrInfo.dstEndPoint = endPoint;
  Set2Bytes(req.addrInfo.aClusterId, gZclClusterOnOff_c);
  req.addrInfo.srcEndPoint = endPoint;
  req.addrInfo.txOptions = gZclTxOptions;
  req.addrInfo.radiusCounter = afDefaultRadius_c;

  /* send the command */
  req.command = command;

  (void)ASL_ZclOnOffReq(&req);
}
void ZdoNwk_ClearSiblingOnNeighborTable(ZdoEvent_t startMode)
{
#if (gRnplusCapability_d && !gEndDevCapability_d)
  uint8_t iIndex;         /* Index to traverse through the neighbor table*/
  neighborTable_t* pNTE;  /* pointer to neighbor table entry */

  /*
    If the starting mode is silent the device should prented that it has been on the
    network all the time and avoid sending the device announce.
  */
  if (startMode == gZdoStartMode_SilentStart_c)
  {
    return;
  }

  /* End device dont have neither siblings or routes. */
  if(NlmeGetRequest(gDevType_c) == gEndDevice_c)
  {
    return;
  }
  /*
    If SP1 is used then clean up the NT table and route table for siblings when a router rejoins
    this ensures that routes are re-established again.
  */
  ResetRouteTable();

  for (iIndex = 0; iIndex < gMaxNeighborTableEntries; iIndex++)
  {
    pNTE = &(gaNeighborTable [ iIndex ]);
    if(pNTE->deviceProperty.bits.relationship == gNeighborIsSibling_c )
    {
      ResetNeighborTableEntry(pNTE);
    }
  }
#endif
  (void)startMode;
}
/*-------------------- Mgmt_NWK_Update_req --------------------
  2.4.3.3.9 Mgmt_NWK_Update_req. (ClusterID=0x0038)

  This command is provided to allow updating of network configuration parameters
  or to request information from devices on network conditions in the local
  operating environment. The destination addressing on this primitive shall be
  unicast or broadcast to all devices for which macRxOnWhenIdle = TRUE.
*/
zbSize_t Mgmt_NWK_Update_req
(
  zbMgmtNwkUpdateRequest_t  *pRequest,
  zbNwkAddr_t               aDestAddr
)
{
  zbSize_t  size = MbrOfs(zbMgmtNwkUpdateRequest_t, ExtraData);


  if (!ZdoGetNwkManagerBitMask(gaServerMask))
  {
    (void) pRequest;
    (void) aDestAddr;
    (void) size;
    return gZero_c;
  }

  if (!IsValidNwkUnicastAddr(aDestAddr) && !IsEqual2Bytes(aDestAddr,gaBroadcastRxOnIdle))
  {
    /*
      Consider it as an invalid request.
    */
    return gZero_c;
  }

  /*
    The values 0x00 and 0x05 are acording to the Table 2.87 Fields of the
    Mgmt_NWK_Update_req Command , since is a the ScanDuration is a uint8 then 
    it is not necesary to make the verification "pRequest->ScanDuration >= 0x00",
    that is why is commented.
  */

  /*
    Do a scan.
  */
  if ( pRequest->ScanDuration <= 0x05)
  {
     return (size + MbrSizeof(zbudata_t, ScanCount));
  }

  /*
    Channel channel.
  */
  else if (pRequest->ScanDuration == 0xfe)
  {
#if gFrequencyAgilityCapability_d
    /*
      This is a special case, is when the application commands the channge with out using
      the state machine.
    */
    if (ZdoGetNwkManagerBitMask(gaServerMask)&&(FA_GetNwkManagerState() == gInitState_c))
    {
      /*
        Place holder to the state machine of the Nwk Manager, to avoid hiting the same
        state many times.
      */
      FA_SetNwkManagerState(gSelfChannelChange_c);

      /*
        Send the same command to our selfs, in order to use the mechanism.
      */
      ASL_Mgmt_NWK_Update_req(NlmeGetRequest(gNwkShortAddress_c), /* To Us. */
                              pRequest->aScanChannels,  /* Same Channel list ot be use. */
                              0xfe,  /* Do a channel change. */
                              pRequest->ExtraData.NwkManagerData.nwkUpdateId);  /* No scan duration, is a channel change. */
    }

    /*
      This will make ZDP send the request to other devices.
    */
    return (size + MbrSizeof(zbNwkManagerData_t, nwkUpdateId));
#endif
  }

  /*
    Update NwkUpdateId and channel list.
  */
  else if(pRequest->ScanDuration == 0xff)
  {
    return (size + MbrSizeof(zbNwkManagerData_t, nwkUpdateId) +
            MbrSizeof(zbNwkManagerData_t, aNwkManagerAddr));
  }

  /*
    For any other value of Scanduration then it only needs the Scan Count.
  */
  return (size + MbrSizeof(zbudata_t, ScanCount));
}
};

ztcIBData_t const maZtcIBData[] = {

  /* Network Information Base Identifiers. r17 - Table 3.41 NWK IB Attributes. */
  {gNwkSequenceNumber_c,                    mZtcIBRO, sizeof(gNibSequenceNumber),                    mIBScalar,                              (void *) &gNibSequenceNumber},
  {gNwkPassiveAckTimeout_c,                 mZtcIBRO, sizeof(gNibPassiveAckTimeout),                 mIBScalar,                              (void *) &gNibPassiveAckTimeout},
  {gNwkMaxBroadcastRetries_c,               mZtcIBRO, sizeof(gNibMaxBroadcastRetries),               mIBScalar,                              (void *) &gNibMaxBroadcastRetries},
  {gNwkMaxChildren_c,                       mZtcIBRO, sizeof(gNibMaxChildren),                       mIBScalar,                              (void *) &gNibMaxChildren},
  {gNwkMaxDepth_c,                          mZtcIBRO, sizeof(gNibMaxDepth),                          mIBScalar,                              (void *) &gNibMaxDepth},
  {gNwkMaxRouter_c,                         mZtcIBRO, sizeof(gNibMaxRouter),                         mIBScalar,                              (void *) &gNibMaxRouter},
  {gNwkNetworkBroadcastDeliveryTime_c,      mZtcIBRO, sizeof(gNibNetworkBroadcastDeliveryTime),      mIBScalar,                              (void *) &gNibNetworkBroadcastDeliveryTime},
  {gNwkReportConstantCost_c,                mZtcIBRO, sizeof(gNibReportConstantCost),                mIBScalar,                              (void *) &gNibReportConstantCost},
  {gNwkRouteDiscoveryRetriesPermitted_c,    mZtcIBRO, sizeof(gNibRouteDiscoveryRetriesPermitted),    mIBScalar,                              (void *) &gNibRouteDiscoveryRetriesPermitted},
  {gNwkSymLink_c,                           mZtcIBRO, sizeof(gNibSymLink),                           mIBScalar,                              (void *) &gNibSymLink},
  {gNwkCapabilityInformation_c,             mZtcIBRW, sizeof(NlmeGetRequest(gNwkCapabilityInformation_c)), mIBScalar,                        (void *) &NlmeGetRequest(gNwkCapabilityInformation_c)},
  {gNwkAddrAlloc_c,                         mZtcIBRO, sizeof(gNibAddrAlloc),                         mIBScalar,                              (void *) &gNibAddrAlloc},
  {gNwkUseTreeRouting_c,                    mZtcIBRO, sizeof(gNibUseTreeRouting),                    mIBScalar,                              (void *) &gNibUseTreeRouting},
  {gNwkManagerAddr_c,                       mZtcIBRW, sizeof(zbNwkAddr_t),                           mIBScalar,                               NlmeGetRequest(gNwkManagerAddr_c)},
  {gNwkTransactionPersistenceTime_c,        mZtcIBRO, sizeof(gNibTransactionPersistenceTime),        mIBScalar,                              (void *) &gNibTransactionPersistenceTime},

/* 
  053474r17 Zigbee Spec.
  Table #3.44  NIB Attributes
  Read-Only in ZigBee, Read-Write in ZigBee Pro 
*/
#if gZigbeeProIncluded_d
  {gNwkShortAddress_c,                      mZtcIBRW, sizeof(NlmeGetRequest(gNwkShortAddress_c)),    mIBScalar,                              (void *) NlmeGetRequest(gNwkShortAddress_c)},
#else
  {gNwkShortAddress_c,                      mZtcIBRW, sizeof(NlmeGetRequest(gNwkShortAddress_c)),    mIBScalar,                              (void *) NlmeGetRequest(gNwkShortAddress_c)},
#endif
/************************************************************************************
* Using the default values of the ApsCahnnelMask and ScandDuration, Generates an
* Nlme command to discover the ZigBee networks that may exist on the current
* channel list.
*
* Interface assumptions:
*   Uses APS channel mask (gApsChannelMask_c)
*
* Return value:
*   NONE.
*
* Revison history:
*   Date   Author  Comments
*  ------  ------  --------
*  280208    MN    Updated
************************************************************************************/
void ZdoNwkMng_GenerateNetworkFormation
(
  void  /*IN: No Input Parameters*/
)
{
  nlmeNetworkFormationReq_t  *pNwkFormationReq;
  zdoNlmeMessage_t *pNwkMsg;
  uint8_t *pChannelList = (uint8_t *)ApsmeGetRequest(gApsChannelMask_c);

#if gComboDeviceCapability_d
  if (NlmeGetRequest(gDevType_c) != gCoordinator_c)
    return;
#endif

  /*
    every single command needs it own buffer to be passed down to next layer.
  */
  pNwkMsg = MSG_AllocType(zdoNlmeMessage_t);
  /*
    If the buffer allocation fails for any reason, that is it, no further
    processing is needed.
  */
  if ( !pNwkMsg )
    return;

  /*
    Create the network formation request and sent to the network Layer.
  */
  pNwkMsg->msgType = gNlmeNetworkFormationRequest_c;

  /*
    Fast access to the memory where the 
  */
  pNwkFormationReq = &pNwkMsg->msgData.networkFormationReq;

#if gComboDeviceCapability_d
  if (NlmeGetRequest(gDevType_c) == gCoordinator_c)
#endif
  {
    /*
      We will use the list from the ED if and only if it is a valid list other wise use
      the current APS channel mask.
    */
    if ((*(uint32_t *)gaScanChannels) != 0)
    {
      /* Use only the channels with the best energy levels for the active scan. */
      pChannelList = gaScanChannels;
    }
  }

  /*
    Using the default channel mask, generate the Formation command.
  */
  FLib_MemCpy(pNwkFormationReq->aScanChannels,
              pChannelList,
              sizeof(ApsmeGetRequest(gApsChannelMask_c)));

  /*
    Get all the parameters neede for this command.
  */
  pNwkFormationReq->scanDuration = gScanDuration_c;
  FLib_MemCpy(&pNwkFormationReq->beaconOrder, &gBeeStackConfig.beaconOrder, 2);
  Copy2Bytes(pNwkFormationReq->aPanId, NlmeGetRequest(gNwkPanId_c));
  pNwkFormationReq->batteryLifeExtension = gBeeStackConfig.batteryLifeExtn;

  if (ZDO_NLME_SapHandler( pNwkMsg ))
  {
    /*
      Catch the error if needed.
    */
  }

}
/************************************************************************************
* Using the default values of the ApsChannelMask and ScanDuration, generates an
* Nlme command to discover the ZigBee networks that may exist on the current
* channel list (issues beacon requests and listens to beacon responses).
*
* Interface assumptions:
*   NONE.
*
* Return value:
*   NONE.
*
* Revison history:
*   Date   Author  Comments
*  ------  ------  --------
*  140708    DG    Updated
************************************************************************************/
void ZdoNwkMng_GenerateNwkDiscoveryReq
(
  void  /* IN: No Input Parameters. */
)
{
  zdoNlmeMessage_t *pNwkMsg;
  nlmeNetworkDiscoveryReq_t *pNwkDiscoveryReq;
  uint8_t *pChannelList = (uint8_t *)ApsmeGetRequest(gApsChannelMask_c);

  /*
    We need to generate a message to Nwk layer, a buffer needs to be allocated.
  */
  pNwkMsg = MSG_AllocType( zdoNlmeMessage_t );
  /*
    For some reason we fail to allocate the memory, no further
    processing can be done.
  */
  if (!pNwkMsg)
    return;

  /*
    We are about to do what in the network layer is named active scan, we need the right
    list depending on the device type.
  */
#if gCoordinatorCapability_d || gComboDeviceCapability_d
#if gComboDeviceCapability_d
  if (NlmeGetRequest(gDevType_c) == gCoordinator_c)
#endif
  {
    /*
      We will use the list from the ED if and only if it is a valid list other wise use
      the current APS channel mask.
    */
    if ((*(uint32_t *)gaScanChannels) != 0)
    {
      /* Use only the channels with the best energy levels for the active scan. */
      pChannelList = gaScanChannels;
    }
  }
#endif

  /*
    Create the network descovery request and sent to the network Layer.
  */
  pNwkMsg->msgType = gNlmeNetworkDiscoveryRequest_c ;

  /*
    Fast access to the memory where the message is build, also is less code.
  */
  pNwkDiscoveryReq =  &pNwkMsg->msgData.networkDiscoveryReq;

  /*
    Set the current and active ApsChannelMask, remember this can be updated
    during the FA process.
  */
  FLib_MemCpy(pNwkDiscoveryReq->aScanChannels,
              pChannelList,
              sizeof(ApsmeGetRequest(gApsChannelMask_c)));

  /*
    Get the default duration to use during the scan, remember that is trasnformed
    to a milliseconds time, down in the Nwk Layer.
  */
  pNwkDiscoveryReq->scanDuration = gScanDuration_c;

  /*
    Pass the command down to the Nwk layer.
  */
  if (ZDO_NLME_SapHandler( pNwkMsg ))
  {
    /*
      Catch the error if needed.
    */
  }

}
void ZDO_NwkManager
(
  nlmeZdoMessage_t *pZdoMsg  /*IN: Message received from ZDO*/
)
{

  nlmeJoinIndication_t  *pJoinIndication;
  uint8_t aNwkAddr[2];
  
  (void)aNwkAddr;
  gMemoryFreedByApplication = FALSE;
  switch (pZdoMsg->msgType)
  {

    /*************************************************************************************
      NLME-Formation.confirm: Formation confirm is only available for PAN Coordinator
      devices or combo devices acting like coordinator.
    **************************************************************************************/
    case gNlmeNetworkFormationConfirm_c:

#if ( gCoordinatorCapability_d || gComboDeviceCapability_d)

#if gComboDeviceCapability_d
      /*
        If a combo device is not acting like a PAN Coordinator should not do any further
        processing.
      */
      if (NlmeGetRequest(gDevType_c) != gCoordinator_c)
      {
        break;
      }
#endif

      /* Send an event to the ZDO state machine informing the fromation status. */
      if (pZdoMsg->msgData.networkFormationConf.status == gZbSuccess_c)
      {
        ZDO_SendEvent(gZdoEvent_FormationSuccess_c);
      }
      else
      {
        ZDO_SendEvent(gZdoEvent_FormationFailure_c);
      }
#endif
    break;

    /*************************************************************************************
      NLME-Discovery.confirm
    **************************************************************************************/
    case gNlmeNetworkDiscoveryConfirm_c:
      /*
        If the device is trying to associate it self to a PAN, the state machine changes
        to be on gZdoDiscoveringNetworksState_c.
      */
      if (ZDO_GetState() == gZdoDiscoveringNetworksState_c)
      {
        ZdoEvent_t event;
        /*
          The discovery information have already been stored by the NWK layer.
          Free up the confirm.
        */
        if(pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor != NULL)
        {
          MSG_Free( pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor );
        }

        /* send an event to state machine task depending on the confirmation */
        event = (pZdoMsg->msgData.networkDiscoveryConf.status == gZbSuccess_c)? gZdoEvent_DiscoverySuccess_c : gZdoEvent_DiscoveryFailure_c;
        ZDO_SendEvent(event);

        /*
          Setting this variable to FALSE means that ZDO will free the message and not the
          application.
        */
        gMemoryFreedByApplication = FALSE;
        break;
      }

      /***********************************************************************************
        For any of this cases the tables does not need to be arround so lets free
        up the memory. IMPORTANT: The tables need to be freed to avoid memory leaks.
      ************************************************************************************/
      NWK_FreeUpDiscoveryTables();

      /*
        If the device is on running state this means that it may be the application the
        one commanding the discovery.
      */
      if(ZDO_IsRunningState())
      {
        /* Reprot the discovery information to hte application. */
        ( void ) ZDP_APP_SapHandler((zdpToAppMessage_t *)pZdoMsg);

        /*
          Setting this variable to TRUE means that the application is responsible of
          freeing the list inside the discovery message.
        */
        gMemoryFreedByApplication = TRUE;
      }

      /*
        Management commands prevent the ZDO stae machine for doing anything but finishing
        the process of the remote command.
      */
      else if (ZDO_GetState() == gZdoRemoteCommandsState_c)
      {
#if gMgmt_NWK_Disc_rsp_d
        /* Generate the response through zdpmanager */
        Zdp_Mgmt_Send_Nwk_disc_conf( pZdoMsg );
#endif
        ZDO_SendEvent(gZdoEvent_ManagementResponse_c);

        /*
          The information was copied in ZDP so the list inside the packet is no longer
          needed.
        */
        if (pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor != NULL)
        {
          MSG_Free( pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor );
        }

        /*
          Setting this variable to FALSE means that all the buffers are free, no need to
          re-free it.
        */
        gMemoryFreedByApplication = FALSE;
      }

      
      else
      {
        /* Clean up the discovery tables in the stack */
        NWK_FreeUpDiscoveryTables();
        if (pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor != NULL)
        {
          MSG_Free( pZdoMsg->msgData.networkDiscoveryConf.pNetworkDescriptor );
        }
        gMemoryFreedByApplication = FALSE;
      }
    break;

    /*************************************************************************************
      NLME-Join.confirm: We have join TO SOME ONE.
    **************************************************************************************/
    case gNlmeJoinConfirm_c:
#if gRouterCapability_d || gEndDevCapability_d || gComboDeviceCapability_d
      /*
        Make sure that the discovery tables have been freed after join request has been
        processed.
      */
      NWK_FreeUpDiscoveryTables();      

      /* If a combo device is not router or end device should not proceed. */
#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gCoordinator_c)
      {
        break;
      }
#endif

      /*
        If the device is already on running state the node may receive the unsolicited
        rejoin response because of and addressconflict, so ignore the join confirm.
      */
      if (ZDO_IsRunningState())
        break;

      /* If the device is not running then force it to parse the confirm. */
      ZDO_SetState(gZdoJoiningState_c);

      /* Send an event to the ZDO state machine informing about the joining state. */
      if( pZdoMsg->msgData.joinConf.status == gZbSuccess_c )
      {
        ZDO_SendEvent(gZdoEvent_JoinSuccess_c);
      }
      else
      {
        ZDO_SendEvent(gZdoEvent_JoinFailure_c);
      }
#endif
    break;

    /*************************************************************************************
      NLME-Join.indication: A device has join TO US.
    **************************************************************************************/
    case gNlmeJoinIndication_c:
      /*
        Do the casting for the message one time and in one place, Code saving.
      */
      pJoinIndication = &pZdoMsg->msgData.joinIndication;

      /*
        To avoid reject packets when the node join and comunicate multi ple times,
        the devices should flush the APS Duplicate table.
      */
      APS_RemoveEntryFromApsDuplicateTable(pJoinIndication->aShortAddress);

      /* Every child joined to us must be record, to avoid lossing it in case of reset. */
      ZdoNwkMng_SaveToNvm(zdoNvmObject_NeighborTable_c);

#if gRnplusCapability_d
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) != gEndDevice_c)
#endif
      {
        /* Remove the old routes to the joining device */
        RemoveRouteEntry(pJoinIndication->aShortAddress);
      }
#endif
#endif


#if gStandardSecurity_d || gHighSecurity_d
      /* If the joining device is associated from scratch erase previous data. */
      if (pJoinIndication->rejoinNetwork == gAssociationJoin_c)
      {
        if (ApsmeGetRequest(gApsDefaultTCKeyType_c) == gTrustCenterLinkKey_c)
        {
          APS_ResetDeviceCounters(pJoinIndication->aExtendedAddress);
        }
        else
        {
          APS_RemoveSecurityMaterialEntry(pJoinIndication->aExtendedAddress);
        }

        /* Setting the last parameter to TRUE will erase APS secure material */
        ZDO_SecClearDeviceData(pJoinIndication->aShortAddress, pJoinIndication->aExtendedAddress, FALSE);
      }
      /*
        If security is active and the joining mode is other that association join,
        no further processing should be done to the join indication.
        Consider the unsecure join.
      */
      //else if ((pJoinIndication->rejoinNetwork == gNwkRejoin_c) && pJoinIndication->secureRejoin)
      //{
        /* Make sure the memory will be freed */
        //gMemoryFreedByApplication = FALSE;

        /* Do not process it further, no transport key will be needed. */
        //return;
      //}
      else if (pJoinIndication->rejoinNetwork == gNwkRejoin_c && !pJoinIndication->secureRejoin)
      {
        /* Reset the Incoming frame counter of the dev that has left. */
        /* Setting the last parameter to TRUE will erase APS secure material */
        if (ApsmeGetRequest(gApsDefaultTCKeyType_c) == gTrustCenterLinkKey_c)
        {
          APS_ResetDeviceCounters(pJoinIndication->aExtendedAddress);
        }
        else
        {
          APS_RemoveSecurityMaterialEntry(pJoinIndication->aExtendedAddress);
        }
        /* Setting the last parameter to TRUE will erase APS secure material */
        ZDO_SecClearDeviceData(pJoinIndication->aShortAddress, pJoinIndication->aExtendedAddress, FALSE);
      }

      /*
        The device must be set as Unauthenticated child in the NT.
      */
      SSP_NwkSetRelationship(pJoinIndication->aExtendedAddress, gUnAuthenticatedChild_c);

      /* Keep the buffer around to be use in the state machine or the application. */
      gMemoryFreedByApplication = TRUE;

/***************************************************
  Trust center specific join indication processing.
****************************************************/
#if gTrustCenter_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (gTrustCenter)
#endif
      {
        /*
          Keep the information, we are going to start the joining state machine.
        */
        MSG_Queue(&gJoinIndicationQueue, pZdoMsg);

        /*
          Tell the ZDO Task that we got a joining device packet and ready for action.
        */
        TS_SendEvent(gZdoTaskID_c, gJoinIndicationArrive_c);
      }
#endif

#if !gTrustCenter_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (!gTrustCenter)
#endif
      {
        uint8_t joiningType;
        bool_t  isHighSecurity = FALSE;
        /*
          Every other device with joining capabilities should report the joining,
          using an APSME-UPDATE-DEVICE.request.
        */
        isHighSecurity = (pJoinIndication->capabilityInformation & gSecurityCapability_c)? TRUE : FALSE;
        if (pJoinIndication->rejoinNetwork == gAssociationJoin_c)
        {
          joiningType = (isHighSecurity)? gHighSecurityDeviceUnsecuredJoin_c : gStandardDeviceUnsecuredJoin_c;
        }
        else if (pJoinIndication->rejoinNetwork == gNwkRejoin_c)
        {
          if (pJoinIndication->secureRejoin)
          {
            joiningType = (isHighSecurity)? gHighSecurityDeviceSecuredReJoin_c : gStandardDeviceSecuredReJoin_c;
          }
          else
          {
            joiningType = (isHighSecurity)? gHighSecurityDeviceUnsecuredRejoin_c : gStandardDeviceUnsecuredRejoin_c;
          }
        }

        // Always send the update device
        ZDO_APSME_Update_Device_request(pJoinIndication->aExtendedAddress,
                                        pJoinIndication->aShortAddress,
                                        joiningType,
                                        pJoinIndication->secureRejoin);
        (void)ZDP_APP_SapHandler((void *)pZdoMsg);
      }
#endif

/* #endif gStandardSecurity_d */
#endif
    break; /*break for join indication*/

    /*************************************************************************************
      NLME-StartRouter.confirm: Every time that a Coordinator or a Router starts, genrates
      a start router confirm.
    **************************************************************************************/
    case gNlmeStartRouterConfirm_c:
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

      /* Combo devices acting like ZED don't need this confirm. */
#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

      /* Indicate router has started (or not) */
      if (pZdoMsg->msgData.startRouterConf.status == gZbSuccess_c)
      {
        ZDO_SendEvent(gZdoEvent_StartRouterSuccess_c);
      }
      else
      {
        ZDO_SendEvent(gZdoEvent_StartRouterFailure_c);
      }
#endif
    break;

    /*************************************************************************************
      NLME-Sync.confirm
    **************************************************************************************/
    case gNlmeSyncConfirm_c:
#if gEndDevCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) != gEndDevice_c)
      {
        break;
      }
#endif
      pZdoMsg->msgType = gSyncConf_c;
      ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );
      /* The application is responsible of freen the buffers. */
      gMemoryFreedByApplication = TRUE;
#endif
    break;

    /*************************************************************************************
      NLME-PermitJoining.confirm
    **************************************************************************************/
    case gNlmePermitJoiningConfirm_c:
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

      if(ZDO_IsRunningState())
      {
        /* let application know about the permit join */
        pZdoMsg->msgType = gPermitjoinConf_c;
        ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );

        /* indicate this SAP handler won't be freeing the memory */
        gMemoryFreedByApplication = TRUE;
      }

#endif
      break;

    /*************************************************************************************
      NLME-DirectJoin.confirm
    **************************************************************************************/
    case gNlmeDirectJoinConfirm_c:
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

      /*
        The may come because the network layer start the direct join and the confirm must
        be pass up to the application.
      */
      if (ZDO_IsRunningState())
      {
        /* Send message on to app. Tell this SAP handler not to free it. */
        (void) ZDP_APP_SapHandler( (void *)pZdoMsg );
        gMemoryFreedByApplication = TRUE;
      }

      else if (ZDO_GetState() == gZdoRemoteCommandsState_c)
      {
        ZDO_SendEvent(gZdoEvent_ManagementResponse_c);
#if gMgmt_Direct_Join_rsp_d && (gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d)
#if gComboDeviceCapability_d
        if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
        {
          break;
        }
#endif
        /* Generate the response through zdpmanager */
        Zdp_Mgmt_Direct_Join_conf( pZdoMsg );
        /* Update the global variable to free the menory */
        gMemoryFreedByApplication = TRUE;
#endif
      }

#endif
      break;

    /*************************************************************************************
      NLME-Leave.indication
    **************************************************************************************/
    case gNlmeLeaveIndication_c:

      /* The local node is the one leaving the network. */
      if (Cmp8BytesToZero(pZdoMsg->msgData.leaveIndication.aDeviceAddress))
      {
        /* Only important to the local leave. Pick an appropiated leaving event. */
        ZdoStopMode_t stopMode;

        /*
          Send event to ZDO state machine to initiate the reset procedure (r11, p272, ln31)
          The devices should not set the default mode to stop the node on a leave indication,
          the default mode send another leave.... and we just left.
        */
        stopMode = gZdoStopModeDefault_c | gZdoStopMode;
        if (pZdoMsg->msgData.leaveIndication.rejoin)
        {
          /* We will come back.! */
          stopMode |= gZdoStopMode_StopAndRestart_c;

          /* We are doing rejoin, we should not clear the tables. */
          stopMode &= ~gZdoStopMode_ResetTables_c;

        } /* End of if (pZdoMsg->msgData.leaveIndication.rejoin) */

        /* Tell ZDO to pull the breaks; */
        ZDO_StopEx(stopMode);
        break;
      } /* End of if (Cmp8BytesToZero(pZdoMsg->msgData.leaveIndication.aDeviceAddress)) */

      /* If we got the indiction and we are waiting for it, return to previous state. */
      if (ZDO_GetState() == gZdoRemoteCommandsState_c)
      {
        ZDO_SendEvent(gZdoEvent_ManagementResponse_c);
      }

#if gStandardSecurity_d || gHighSecurity_d
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

      /*
        Reset the Incoming frame counter of the dev that has left.
      */
      SSP_NwkResetDeviceFrameCounter( pZdoMsg->msgData.leaveIndication.aDeviceAddress );

      /*
        If the device is Link capable remove the link key information if it exists.
      */
      APS_RemoveSecurityMaterialEntry(pZdoMsg->msgData.leaveIndication.aDeviceAddress);

      /*
        Let the trust center know about the leaving device.
      */
//      if (!IsSelfIeeeAddress(ApsmeGetRequest(gApsTrustCenterAddress_c)))
#if !gTrustCenter_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
       if (!gTrustCenter)
#endif
      
      {
        ZDO_APSME_Update_Device_request(pZdoMsg->msgData.leaveIndication.aDeviceAddress,
                                        APS_GetNwkAddress(pZdoMsg->msgData.leaveIndication.aDeviceAddress, aNwkAddr),
                                        gDeviceLeft_c, 0x00);
      }
#endif      
#endif
#endif

     /* ZEDs dont porcess the removing of the children and removing of the routes. */
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d
#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

#if gRnplusCapability_d
      /* Remove the old routes for the leaving device */
      RemoveRouteEntry(APS_GetNwkAddress(pZdoMsg->msgData.leaveIndication.aDeviceAddress, aNwkAddr));
#endif

      /* Clean up address map if there is no bindings referencing address map entry
         consider deleting all bindings first.
       */
      (void)APS_RemoveDeviceFromAddressMap(pZdoMsg->msgData.leaveIndication.aDeviceAddress);

      /* Tells the network layer to remove the leaving device from its tables. */
      NWK_RemoveChildRecords(pZdoMsg->msgData.leaveIndication.aDeviceAddress);
#endif

      /*
        Save the network data, to preserve that the leaving device is gone. Plus the
        counters for security (NWK and APS)that got reset.
      */
      ZdoNwkMng_SaveToNvm(zdoNvmObject_All_c);
    break;

    /*************************************************************************************
      NLME-Leave.confirm
    **************************************************************************************/
    case gNlmeLeaveConfirm_c:
      /* If we have received a management leave request, send the response */
      if (ZDO_GetState() == gZdoRemoteCommandsState_c)
      {
#if gMgmt_Leave_rsp_d
        Zdp_Mgmt_Send_leave_conf(pZdoMsg);
        /* The momery has been handled by the next higher layer. */
        gMemoryFreedByApplication = TRUE;
#endif
        ZDO_SendEvent(gZdoEvent_ManagementResponse_c);
      }

      /* The local node is the one leaving the network. */
      if (Cmp8BytesToZero(pZdoMsg->msgData.leaveConf.aDeviceAddress))
      {
        /* The self leave is handle in the indication. */
        break;
      }

#if gStandardSecurity_d || gHighSecurity_d
#if gCoordinatorCapability_d || gRouterCapability_d || gComboDeviceCapability_d

#if gComboDeviceCapability_d
      if (NlmeGetRequest(gDevType_c) == gEndDevice_c)
      {
        break;
      }
#endif

      /*
        Reset the Incoming frame counter of the dev that has left.
      */
      SSP_NwkResetDeviceFrameCounter( pZdoMsg->msgData.leaveIndication.aDeviceAddress );

      /*
        If the device is Link capable remove the link key information if it exists.
      */
      APS_RemoveSecurityMaterialEntry(pZdoMsg->msgData.leaveIndication.aDeviceAddress);

      /*
        Let the trust center know about the leaving device.
      */
      ZDO_APSME_Update_Device_request(pZdoMsg->msgData.leaveIndication.aDeviceAddress,
                                      APS_GetNwkAddress(pZdoMsg->msgData.leaveIndication.aDeviceAddress, aNwkAddr),
                                      gDeviceLeft_c, 0x00);

      /*
        Tells the network layer to remove the leaving device from its tables.
      */
      NWK_RemoveChildRecords(pZdoMsg->msgData.leaveIndication.aDeviceAddress);
#endif

/* #endif gStandardSecurity_d */
#endif
    break;

    /*************************************************************************************
      NLME-RouteDiscovery.confirm
    **************************************************************************************/
    case  gNlmeNetworkStatusCnf_c:
    case  gNlmeRouteDiscoveryCnf_c:
      /* This packet will be freed by the application*/
      gMemoryFreedByApplication = TRUE;
      /* Pass the packet to the App */
      ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );
    break;

    /*************************************************************************************
      NLME-EnergyScan.confirm: An Energy Scan Confirm has come back. Was it due to the
      forming process, or due to FA/ZDP.
    **************************************************************************************/
    case  gNlmeEnergyScanConfirm_c:           
      
      if(ZDO_GetState() == gZdoDiscoveringNetworksState_c)
      {
        if (pZdoMsg->msgData.EnergyScanConf.status == gZbSuccess_c)
        {
          ZDO_SendEvent(gZdoEvent_EnergyScanComplete_c);
        }
        else
        {
          ZDO_StopEx(gZdoStopModeDefault_c);
        }
      }

      /* Send to application layer */
      ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );

      /* Update the global variable to free the memory */
      gMemoryFreedByApplication = TRUE;
    break;

    case gNlmeNetworkStatusInd_c:
    case gNlmeTxReport_c:
      /* Send to application layer */
      ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );

      /* Update the global variable to free the memory */
      gMemoryFreedByApplication = TRUE;
    break;

    case gNwkProcessFrameConf_c:
#if gStandardSecurity_d || gHighSecurity_d
      /* Send to application layer */
      ( void ) ZDP_APP_SapHandler( (void *)pZdoMsg );

      /* Update the global variable to free the memory */
      gMemoryFreedByApplication = TRUE;
#else
      gMemoryFreedByApplication = FALSE;
#endif
    break;

    default:
    break;
  } /* End of switch */
}
/*
  Call on the network layer to (re)join the network. Includes orphan join, 
  associate join, etc...
*/
void ZdoNwkMng_GenerateNwkJoinRequest(zbNwkJoinMode_t joinMode)
{
  zdoNlmeMessage_t *pMsg;
  nlmeJoinReq_t *pJoinReq;
  uint8_t *pExtendedPan = (uint8_t *)NlmeGetRequest(gNwkExtendedPanId_c);

  /* allocate the request */
  pMsg = MSG_AllocType(zdoNlmeMessage_t);

  if (!pMsg)
  {
    return;
  }

  /* Create the network Join request and sent to the network Layer */
  pMsg->msgType = gNlmeJoinRequest_c;
  pJoinReq = &pMsg->msgData.joinReq;

  FLib_MemCpy(pJoinReq->aScanChannels,
              ApsmeGetRequest(gApsChannelMask_c),
              sizeof(ApsmeGetRequest(gApsChannelMask_c)));

  gZDO_SecureRejoin = ApsmeGetRequest(gApsUseInsecureJoin_c);
  /*
    By default the node will try to keep the behavior established by the SAS attribute,
    The SAS attribute canbe override by the application through the IB Set and Get.
  */
  pJoinReq->securityEnable = ApsmeGetRequest(gApsUseInsecureJoin_c)? FALSE : TRUE;
#if gStandardSecurity_d || gHighSecurity_d
  /* If we are trying to send a secure packet, then, check if we have a valid Nwk key. */
  if (pJoinReq->securityEnable)
  {
    pJoinReq->securityEnable = SSP_NwkGotValidKey();
  }

  /* If the rejoin is allowed unsecured then change the APSIB until authentication has arrive. */
  if (!pJoinReq->securityEnable)
  {
    ApsmeSetRequest(gApsUseInsecureJoin_c, TRUE);
  }
#endif

#if gComboDeviceCapability_d
  pJoinReq->joinAsRouter = (NlmeGetRequest( gDevType_c ) == gRouter_c)? TRUE : FALSE;
#elif ( gRouterCapability_d )
  pJoinReq->joinAsRouter = TRUE;
#else /*gRouterCapability_d*/
  pJoinReq->joinAsRouter = FALSE;
#endif /*gRouterCapability_d*/

  pJoinReq->rejoinNetwork = joinMode;
  if (joinMode == gZdoStartMode_NwkRejoin_c)
  {
    pExtendedPan = (uint8_t *)ApsmeGetRequest(gApsUseExtendedPANID_c);
  }

  Copy8Bytes( pJoinReq->aExtendedPanId, pExtendedPan);
  pJoinReq->scanDuration = gScanDuration_c;
  pJoinReq->powerSource = ((gBeeStackConfig.currPowerSourceAndLevel & 0x01)? 0 : 1);

  pJoinReq->rxOnWhenIdle = ((IsLocalDeviceReceiverOnWhenIdle())? TRUE : FALSE);

  ( void ) ZDO_NLME_SapHandler( pMsg );
}