CC2530,zigbee,协议栈,代码集(ZDO,ZMac,主函数,输出)

10 篇文章 1 订阅
8 篇文章 1 订阅

ZDSecMgr.c


#ifdef __cplusplus
extern "C"
{
#endif

#include "ZComdef.h"
#include "OSAL.h"
#include "OSAL_NV.h"
#include "ZGlobals.h"
#include "ssp.h"
#include "nwk_globals.h"
#include "nwk.h"
#include "NLMEDE.h"
#include "AddrMgr.h"
#include "AssocList.h"
#include "APSMEDE.h"
#include "ZDConfig.h"
#include "ZDSecMgr.h"

// maximum number of devices managed by this Security Manager
#if !defined ( ZDSECMGR_DEVICE_MAX )
  #define ZDSECMGR_DEVICE_MAX 3
#endif

// total number of preconfigured devices (EXT address, MASTER key)
//devtag.pro.security
//#define ZDSECMGR_PRECONFIG_MAX ZDSECMGR_DEVICE_MAX
#define ZDSECMGR_PRECONFIG_MAX 0

// maximum number of MASTER keys this device may hold
#define ZDSECMGR_MASTERKEY_MAX ZDSECMGR_DEVICE_MAX

// maximum number of LINK keys this device may store
#define ZDSECMGR_ENTRY_MAX ZDSECMGR_DEVICE_MAX

// total number of devices under control - authentication, SKKE, etc.
#define ZDSECMGR_CTRL_MAX ZDSECMGR_DEVICE_MAX

// total number of stored devices
#if !defined ( ZDSECMGR_STORED_DEVICES )
  #define ZDSECMGR_STORED_DEVICES 3
#endif

// Total number of preconfigured trust center link key
#if !defined ( ZDSECMGR_TC_DEVICE_MAX )
  #define ZDSECMGR_TC_DEVICE_MAX 1
#endif

#if ( ZDSECMGR_TC_DEVICE_MAX < 1 ) || ( ZDSECMGR_TC_DEVICE_MAX > 255 )
  #error "ZDSECMGR_TC_DEVICE_MAX shall be between 1 and 255 !"
#endif

#define ZDSECMGR_CTRL_NONE       0
#define ZDSECMGR_CTRL_INIT       1
#define ZDSECMGR_CTRL_TK_MASTER  2
#define ZDSECMGR_CTRL_SKKE_INIT  3
#define ZDSECMGR_CTRL_SKKE_WAIT  4
#define ZDSECMGR_CTRL_SKKE_DONE  5
#define ZDSECMGR_CTRL_SKKE_FAIL  6
#define ZDSECMGR_CTRL_TK_NWK     7

#define ZDSECMGR_CTRL_BASE_CNTR      1
#define ZDSECMGR_CTRL_SKKE_INIT_CNTR 1
#define ZDSECMGR_CTRL_TK_NWK_CNTR    1

// set SKA slot maximum
#define ZDSECMGR_SKA_SLOT_MAX 1

// APSME Stub Implementations
#define ZDSecMgrMasterKeyGet   APSME_MasterKeyGet
#define ZDSecMgrLinkKeySet     APSME_LinkKeySet
#define ZDSecMgrLinkKeyNVIdGet APSME_LinkKeyNVIdGet
#define ZDSecMgrKeyFwdToChild  APSME_KeyFwdToChild
#define ZDSecMgrIsLinkKeyValid APSME_IsLinkKeyValid

typedef struct
{
  uint8 extAddr[Z_EXTADDR_LEN];
  uint8 key[SEC_KEY_LEN];
} ZDSecMgrPreConfigData_t;

typedef struct
{
  uint16 ami;
  uint8  key[SEC_KEY_LEN];
} ZDSecMgrMasterKeyData_t;

typedef struct
{
  uint16            ami;
  uint16            keyNvId;   // index to the Link Key table in NV
  ZDSecMgr_Authentication_Option authenticateOption;
} ZDSecMgrEntry_t;

typedef struct
{
  ZDSecMgrEntry_t* entry;
  uint16           parentAddr;
  uint8            secure;
  uint8            state;
  uint8            cntr;
} ZDSecMgrCtrl_t;

typedef struct
{
  uint16          nwkAddr;
  uint8*          extAddr;
  uint16          parentAddr;
  uint8           secure;
  uint8           devStatus;
  ZDSecMgrCtrl_t* ctrl;
} ZDSecMgrDevice_t;

#if 0 // Taken out because the following functionality is only used for test
      // purpose. A more efficient (above) way is used. It can be put
      // back in if customers request for a white/black list feature.
uint8 ZDSecMgrStoredDeviceList[ZDSECMGR_STORED_DEVICES][Z_EXTADDR_LEN] =
{
  { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
};
#endif

uint8 ZDSecMgrTCExtAddr[Z_EXTADDR_LEN]=
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

// Key data is put in CONST area for security reasons
CONST uint8 ZDSecMgrTCMasterKey[SEC_KEY_LEN] =
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x89,0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB};

uint8 ZDSecMgrTCAuthenticated = FALSE;

//devtag.pro.security - remove this
#if ( ZDSECMGR_PRECONFIG_MAX != 0 )
const ZDSecMgrPreConfigData_t ZDSecMgrPreConfigData[ZDSECMGR_PRECONFIG_MAX] =
{
  {
    // extAddr
    {0x7C,0x01,0x12,0x13,0x14,0x15,0x16,0x17},

    // key
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
  },
  {
    // extAddr
    {0x84,0x03,0x00,0x00,0x00,0x4B,0x12,0x00},

    // key
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
  },
  {
    // extAddr
    {0x3E,0x01,0x12,0x13,0x14,0x15,0x16,0x17},

    // key
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
  },
};
#endif // ( ZDSECMGR_PRECONFIG_MAX != 0 )

ZDSecMgrEntry_t* ZDSecMgrEntries  = NULL;
ZDSecMgrCtrl_t*  ZDSecMgrCtrlData = NULL;
void ZDSecMgrAddrMgrUpdate( uint16 ami, uint16 nwkAddr );
void ZDSecMgrAddrMgrCB( uint8 update, AddrMgrEntry_t* newEntry, AddrMgrEntry_t* oldEntry );

uint8 ZDSecMgrPermitJoiningEnabled;
uint8 ZDSecMgrPermitJoiningTimed;

APSME_TCLinkKey_t TrustCenterLinkKey;

APSME_ApsLinkKeyFrmCntr_t ApsLinkKeyFrmCntr[ZDSECMGR_ENTRY_MAX];
APSME_TCLinkKeyFrmCntr_t TCLinkKeyFrmCntr[ZDSECMGR_TC_DEVICE_MAX];

void ZDSecMgrMasterKeyInit( void );

ZStatus_t ZDSecMgrAddrStore( uint16 nwkAddr, uint8* extAddr, uint16* ami );
ZStatus_t ZDSecMgrExtAddrStore( uint16 nwkAddr, uint8* extAddr, uint16* ami );
ZStatus_t ZDSecMgrExtAddrLookup( uint8* extAddr, uint16* ami );

uint8 ZDSecMgrTCExtAddrCheck( uint8* extAddr );
void ZDSecMgrTCDataLoad( uint8* extAddr );

ZStatus_t ZDSecMgrMasterKeyLookup( uint16 ami, uint16* pKeyNvId );
ZStatus_t ZDSecMgrMasterKeyStore( uint16 ami, uint8* key );

void ZDSecMgrEntryInit(uint8 state);
ZStatus_t ZDSecMgrEntryLookup( uint16 nwkAddr, ZDSecMgrEntry_t** entry );
ZStatus_t ZDSecMgrEntryLookupAMI( uint16 ami, ZDSecMgrEntry_t** entry );
ZStatus_t ZDSecMgrEntryLookupExt( uint8* extAddr, ZDSecMgrEntry_t** entry );
ZStatus_t ZDSecMgrEntryLookupExtGetIndex( uint8* extAddr, ZDSecMgrEntry_t** entry, uint16* entryIndex );
ZStatus_t ZDSecMgrEntryLookupAMIGetIndex( uint16 ami, uint16* entryIndex );
void ZDSecMgrEntryFree( ZDSecMgrEntry_t* entry );
ZStatus_t ZDSecMgrEntryNew( ZDSecMgrEntry_t** entry );
ZStatus_t ZDSecMgrAuthenticationSet( uint8* extAddr, ZDSecMgr_Authentication_Option option );
void ZDSecMgrApsLinkKeyInit(void);
#if defined ( NV_RESTORE )
static void ZDSecMgrWriteNV(void);
static void ZDSecMgrRestoreFromNV(void);
static void ZDSecMgrUpdateNV( uint16 index );
#endif

void ZDSecMgrCtrlInit( void );
void ZDSecMgrCtrlRelease( ZDSecMgrCtrl_t* ctrl );
void ZDSecMgrCtrlLookup( ZDSecMgrEntry_t* entry, ZDSecMgrCtrl_t** ctrl );
void ZDSecMgrCtrlSet( ZDSecMgrDevice_t* device,
                      ZDSecMgrEntry_t*  entry,
                      ZDSecMgrCtrl_t*   ctrl );
ZStatus_t ZDSecMgrCtrlAdd( ZDSecMgrDevice_t* device, ZDSecMgrEntry_t*  entry );
void ZDSecMgrCtrlTerm( ZDSecMgrEntry_t* entry );
ZStatus_t ZDSecMgrCtrlReset( ZDSecMgrDevice_t* device,
                             ZDSecMgrEntry_t*  entry );

ZStatus_t ZDSecMgrMasterKeyLoad( uint8* extAddr, uint8* key );
ZStatus_t ZDSecMgrAppKeyGet( uint16  initNwkAddr,
                             uint8*  initExtAddr,
                             uint16  partNwkAddr,
                             uint8*  partExtAddr,
                             uint8** key,
                             uint8*  keyType );
void ZDSecMgrAppKeyReq( ZDO_RequestKeyInd_t* ind );
ZStatus_t ZDSecMgrEstablishKey( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrSendMasterKey( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrSendNwkKey( ZDSecMgrDevice_t* device );
void ZDSecMgrNwkKeyInit(uint8 setDefault);

void ZDSecMgrDeviceEntryRemove( ZDSecMgrEntry_t* entry );
ZStatus_t ZDSecMgrDeviceEntryAdd( ZDSecMgrDevice_t* device, uint16 ami );

void ZDSecMgrDeviceCtrlHandler( ZDSecMgrDevice_t* device );
void ZDSecMgrDeviceCtrlSetup( ZDSecMgrDevice_t* device );
void ZDSecMgrDeviceCtrlUpdate( uint8* extAddr, uint8 state );

void ZDSecMgrDeviceRemove( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceValidateSKKE( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceValidateRM( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceValidateCM( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceValidate( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceJoin( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceJoinDirect( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceJoinFwd( ZDSecMgrDevice_t* device );
ZStatus_t ZDSecMgrDeviceNew( ZDSecMgrDevice_t* device );

void ZDSecMgrAssocDeviceAuth( associated_devices_t* assoc );

void ZDSecMgrAuthInitiate( uint8* responder );
void ZDSecMgrAuthNwkKey( void );

void APSME_TCLinkKeyInit( uint8 setDefault );
uint8 APSME_IsDefaultTCLK( uint8 *extAddr );

void ZDSecMgrMasterKeyInit( void )
{
  uint16 index;
  ZDSecMgrMasterKeyData_t   masterKeyData;

  masterKeyData.ami = INVALID_NODE_ADDR;

  osal_memset( &masterKeyData.key, 0x00, SEC_KEY_LEN );

  for ( index = 0; index < ZDSECMGR_MASTERKEY_MAX; index++ )
  {
    if ( osal_nv_item_init( (ZCD_NV_MASTER_KEY_DATA_START + index),
                       sizeof(ZDSecMgrMasterKeyData_t), &masterKeyData) == SUCCESS)
    {
      // the item already exists in NV just needs to be set to default values
      osal_nv_write( (ZCD_NV_MASTER_KEY_DATA_START + index), 0,
                      sizeof(ZDSecMgrMasterKeyData_t), &masterKeyData );
    }
  }
}


ZStatus_t ZDSecMgrAddrStore( uint16 nwkAddr, uint8* extAddr, uint16* ami )
{
  ZStatus_t      status;
  AddrMgrEntry_t entry;


  // add entry
  entry.user    = ADDRMGR_USER_SECURITY;
  entry.nwkAddr = nwkAddr;
  AddrMgrExtAddrSet( entry.extAddr, extAddr );

  if ( AddrMgrEntryUpdate( &entry ) == TRUE )
  {
    // return successful results
    *ami   = entry.index;
    status = ZSuccess;
  }
  else
  {
    // return failed results
    *ami   = entry.index;
    status = ZNwkUnknownDevice;
  }

  return status;
}

ZStatus_t ZDSecMgrExtAddrStore( uint16 nwkAddr, uint8* extAddr, uint16* ami )
{
  ZStatus_t      status;
  AddrMgrEntry_t entry;


  // add entry
  entry.user    = ADDRMGR_USER_SECURITY;
  entry.nwkAddr = nwkAddr;
  AddrMgrExtAddrSet( entry.extAddr, extAddr );

  if ( AddrMgrEntryUpdate( &entry ) == TRUE )
  {
    // return successful results
    *ami   = entry.index;
    status = ZSuccess;
  }
  else
  {
    // return failed results
    *ami   = entry.index;
    status = ZNwkUnknownDevice;
  }

  return status;
}

ZStatus_t ZDSecMgrExtAddrLookup( uint8* extAddr, uint16* ami )
{
  ZStatus_t      status;
  AddrMgrEntry_t entry;


  // lookup entry
  entry.user = ADDRMGR_USER_SECURITY;
  AddrMgrExtAddrSet( entry.extAddr, extAddr );

  if ( AddrMgrEntryLookupExt( &entry ) == TRUE )
  {
    // return successful results
    *ami   = entry.index;
    status = ZSuccess;
  }
  else
  {
    // return failed results
    *ami   = entry.index;
    status = ZNwkUnknownDevice;
  }

  return status;
}

ZStatus_t ZDSecMgrAddrClear( uint8* extAddr )
{
  ZStatus_t status;
  uint16 entryAmi;

  // get Address Manager Index
  status = ZDSecMgrExtAddrLookup( extAddr, &entryAmi );

  if ( status == ZSuccess )
  {
    AddrMgrEntry_t addrEntry;

    // Clear SECURITY User bit from the address manager
    addrEntry.user = ADDRMGR_USER_SECURITY;
    addrEntry.index = entryAmi;

    if ( AddrMgrEntryRelease( &addrEntry ) != TRUE )
    {
      // return failure results
      status = ZFailure;
    }
  }

  return status;
}

ZStatus_t ZDSecMgrMasterKeyLookup( uint16 ami, uint16* pKeyNvId )
{
  uint16 index;
  ZDSecMgrMasterKeyData_t masterKeyData;


  for ( index = 0; index < ZDSECMGR_MASTERKEY_MAX ; index++ )
  {
    // Read entry index of the Master key table from NV
    osal_nv_read( (ZCD_NV_MASTER_KEY_DATA_START + index), 0,
                  sizeof(ZDSecMgrMasterKeyData_t), &masterKeyData );

    if ( masterKeyData.ami == ami )
    {
      // return successful results
      *pKeyNvId   = ZCD_NV_MASTER_KEY_DATA_START + index;

      // clear copy of key in RAM
      osal_memset(&masterKeyData, 0x00, sizeof(ZDSecMgrMasterKeyData_t));

      return ZSuccess;
    }
  }

  *pKeyNvId = SEC_NO_KEY_NV_ID;

  // clear copy of key in RAM
  osal_memset(&masterKeyData, 0x00, sizeof(ZDSecMgrMasterKeyData_t));

  return ZNwkUnknownDevice;
}

ZStatus_t ZDSecMgrMasterKeyStore( uint16 ami, uint8* key )
{
  uint16    index;
  ZDSecMgrMasterKeyData_t   masterKeyData;


  for ( index = 0; index < ZDSECMGR_MASTERKEY_MAX ; index++ )
  {
    // Read entry index of the Master key table from NV
    osal_nv_read( (ZCD_NV_MASTER_KEY_DATA_START + index), 0,
                   sizeof(ZDSecMgrMasterKeyData_t), &masterKeyData );

    if ( masterKeyData.ami == INVALID_NODE_ADDR )
    {
      // store EXT address index
      masterKeyData.ami = ami;

      if ( key != NULL )
      {
        osal_memcpy( masterKeyData.key, key,  SEC_KEY_LEN );
      }
      else
      {
        osal_memset( masterKeyData.key, 0, SEC_KEY_LEN );
      }

      // set new values in NV
      osal_nv_write( (ZCD_NV_MASTER_KEY_DATA_START + index), 0,
                      sizeof(ZDSecMgrMasterKeyData_t), &masterKeyData );

      // clear copy of key in RAM
      osal_memset( &masterKeyData, 0x00, sizeof(ZDSecMgrMasterKeyData_t) );

      // return successful results
      return ZSuccess;
    }
  }

  // clear copy of key in RAM
  osal_memset( &masterKeyData, 0x00, sizeof(ZDSecMgrMasterKeyData_t) );

  return ZNwkUnknownDevice;
}

void ZDSecMgrEntryInit(uint8 state)
{
  if (ZDSecMgrEntries == NULL)
  {
    uint16 index;

    if ((ZDSecMgrEntries = osal_mem_alloc(sizeof(ZDSecMgrEntry_t) * ZDSECMGR_ENTRY_MAX)) == NULL)
    {
      return;
    }

    for (index = 0; index < ZDSECMGR_ENTRY_MAX; index++)
    {
      ZDSecMgrEntries[index].ami = INVALID_NODE_ADDR;

      ZDSecMgrEntries[index].keyNvId = SEC_NO_KEY_NV_ID;
    }
  }

#if defined NV_RESTORE
  if (state == ZDO_INITDEV_RESTORED_NETWORK_STATE)
  {
    ZDSecMgrRestoreFromNV();
  }
#else
  (void)state;
#endif
}

ZStatus_t ZDSecMgrEntryLookup( uint16 nwkAddr, ZDSecMgrEntry_t** entry )
{
  uint16         index;
  AddrMgrEntry_t addrMgrEntry;

  // initialize results
  *entry = NULL;

  // verify data is available
  if ( ZDSecMgrEntries != NULL )
  {
    addrMgrEntry.user    = ADDRMGR_USER_SECURITY;
    addrMgrEntry.nwkAddr = nwkAddr;

    if ( AddrMgrEntryLookupNwk( &addrMgrEntry ) == TRUE )
    {
      for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
      {
        if ( addrMgrEntry.index == ZDSecMgrEntries[index].ami )
        {
          // return successful results
          *entry = &ZDSecMgrEntries[index];

          // break from loop
          return ZSuccess;
        }
      }
    }
  }

  return ZNwkUnknownDevice;
}

ZStatus_t ZDSecMgrEntryLookupAMI( uint16 ami, ZDSecMgrEntry_t** entry )
{
  uint16 index;

  // initialize results
  *entry = NULL;

  // verify data is available
  if ( ZDSecMgrEntries != NULL )
  {
    for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
    {
      if ( ZDSecMgrEntries[index].ami == ami )
      {
        // return successful results
        *entry = &ZDSecMgrEntries[index];

        // break from loop
        return ZSuccess;
      }
    }
  }

  return ZNwkUnknownDevice;
}

ZStatus_t ZDSecMgrEntryLookupExt( uint8* extAddr, ZDSecMgrEntry_t** entry )
{
  ZStatus_t status;
  uint16    ami;

  // initialize results
  *entry = NULL;
  status = ZNwkUnknownDevice;

  // lookup address index
  if ( ZDSecMgrExtAddrLookup( extAddr, &ami ) == ZSuccess )
  {
    status = ZDSecMgrEntryLookupAMI( ami, entry );
  }

  return status;
}

ZStatus_t ZDSecMgrEntryLookupExtGetIndex( uint8* extAddr, ZDSecMgrEntry_t** entry, uint16* entryIndex )
{
  uint16 ami;
  uint16 index;

  // lookup address index
  if ( ZDSecMgrExtAddrLookup( extAddr, &ami ) == ZSuccess )
  {
    // verify data is available
    if ( ZDSecMgrEntries != NULL )
    {
      for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
      {
        if ( ZDSecMgrEntries[index].ami == ami )
        {
          // return successful results
          *entry = &ZDSecMgrEntries[index];
          *entryIndex = index;

          // break from loop
          return ZSuccess;
        }
      }
    }
  }

  return ZNwkUnknownDevice;
}

ZStatus_t ZDSecMgrEntryLookupAMIGetIndex( uint16 ami, uint16* entryIndex )
{
  uint16 index;

  // verify data is available
  if ( ZDSecMgrEntries != NULL )
  {
    for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
    {
      if ( ZDSecMgrEntries[index].ami == ami )
      {
        // return successful results
        *entryIndex = index;

        // break from loop
        return ZSuccess;
      }
    }
  }

  return ZNwkUnknownDevice;
}

void ZDSecMgrEntryFree( ZDSecMgrEntry_t* entry )
{
  APSME_LinkKeyData_t   *pApsLinkKey = NULL;

#if defined ( NV_RESTORE )
  ZStatus_t status;
  uint16 entryIndex;

  status = ZDSecMgrEntryLookupAMIGetIndex( entry->ami, &entryIndex );
#endif

  pApsLinkKey = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

  if (pApsLinkKey != NULL)
  {
    osal_memset( pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t) );

    // Clear the APS Link key in NV
    osal_nv_write( entry->keyNvId, 0,
                        sizeof(APSME_LinkKeyData_t), pApsLinkKey);

    // set entry to invalid Key
    entry->keyNvId = SEC_NO_KEY_NV_ID;

    osal_mem_free(pApsLinkKey);
  }

  // marking the entry as INVALID_NODE_ADDR
  entry->ami = INVALID_NODE_ADDR;

  // set to default value
  entry->authenticateOption = ZDSecMgr_Not_Authenticated;

#if defined ( NV_RESTORE )
  if ( status == ZSuccess )
  {
    ZDSecMgrUpdateNV(entryIndex);
  }
#endif
}

ZStatus_t ZDSecMgrEntryNew( ZDSecMgrEntry_t** entry )
{
  uint16 index;

  // initialize results
  *entry = NULL;

  // verify data is available
  if ( ZDSecMgrEntries != NULL )
  {
    // find available entry
    for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
    {
      if ( ZDSecMgrEntries[index].ami == INVALID_NODE_ADDR )
      {
        // return successful result
        *entry = &ZDSecMgrEntries[index];

        // Set the authentication option to default
        ZDSecMgrEntries[index].authenticateOption = ZDSecMgr_Not_Authenticated;

        // break from loop
        return ZSuccess;
      }
    }
  }

  return ZNwkUnknownDevice;
}

void ZDSecMgrCtrlInit( void )
{
  uint16 size;
  uint16 index;

  // allocate entry data
  size = (short)( sizeof(ZDSecMgrCtrl_t) * ZDSECMGR_CTRL_MAX );

  ZDSecMgrCtrlData = osal_mem_alloc( size );

  // initialize data
  if ( ZDSecMgrCtrlData != NULL )
  {
    for( index = 0; index < ZDSECMGR_CTRL_MAX; index++ )
    {
      ZDSecMgrCtrlData[index].state = ZDSECMGR_CTRL_NONE;
    }
  }
}

void ZDSecMgrCtrlRelease( ZDSecMgrCtrl_t* ctrl )
{
  // should always be enough entry control data
  ctrl->state = ZDSECMGR_CTRL_NONE;
}

void ZDSecMgrCtrlLookup( ZDSecMgrEntry_t* entry, ZDSecMgrCtrl_t** ctrl )
{
  uint16 index;

  // initialize search results
  *ctrl = NULL;

  // verify data is available
  if ( ZDSecMgrCtrlData != NULL )
  {
    for ( index = 0; index < ZDSECMGR_CTRL_MAX; index++ )
    {
      // make sure control data is in use
      if ( ZDSecMgrCtrlData[index].state != ZDSECMGR_CTRL_NONE )
      {
        // check for entry match
        if ( ZDSecMgrCtrlData[index].entry == entry )
        {
          // return this control data
          *ctrl = &ZDSecMgrCtrlData[index];

          // break from loop
          return;
        }
      }
    }
  }
}

void ZDSecMgrCtrlSet( ZDSecMgrDevice_t* device,
                      ZDSecMgrEntry_t*  entry,
                      ZDSecMgrCtrl_t*   ctrl )
{
  // set control date
  ctrl->parentAddr = device->parentAddr;
  ctrl->secure     = device->secure;
  ctrl->entry      = entry;
  ctrl->state      = ZDSECMGR_CTRL_INIT;
  ctrl->cntr       = 0;

  // set device pointer
  device->ctrl = ctrl;
}

ZStatus_t ZDSecMgrCtrlAdd( ZDSecMgrDevice_t* device, ZDSecMgrEntry_t*  entry )
{
  uint16 index;

  // verify data is available
  if ( ZDSecMgrCtrlData != NULL )
  {
    // look for an empty slot
    for ( index = 0; index < ZDSECMGR_CTRL_MAX; index++ )
    {
      if ( ZDSecMgrCtrlData[index].state == ZDSECMGR_CTRL_NONE )
      {
        // return successful results
        ZDSecMgrCtrlSet( device, entry, &ZDSecMgrCtrlData[index] );

        // break from loop
        return ZSuccess;
      }
    }
  }

  return ZNwkUnknownDevice;
}

void ZDSecMgrCtrlTerm( ZDSecMgrEntry_t* entry )
{
  ZDSecMgrCtrl_t* ctrl;

  // remove device from control data
  ZDSecMgrCtrlLookup ( entry, &ctrl );

  if ( ctrl != NULL )
  {
    ZDSecMgrCtrlRelease ( ctrl );
  }
}

ZStatus_t ZDSecMgrCtrlReset( ZDSecMgrDevice_t* device, ZDSecMgrEntry_t* entry )
{
  ZStatus_t       status;
  ZDSecMgrCtrl_t* ctrl;

  // initialize results
  status = ZNwkUnknownDevice;

  // look for a match for the entry
  ZDSecMgrCtrlLookup( entry, &ctrl );

  if ( ctrl != NULL )
  {
    ZDSecMgrCtrlSet( device, entry, ctrl );

    status = ZSuccess;
  }
  else
  {
    status = ZDSecMgrCtrlAdd( device, entry );
  }

  return status;
}

ZStatus_t ZDSecMgrMasterKeyLoad( uint8* extAddr, uint8* key )
{
  ZStatus_t status;
  uint16 ami;
  uint16 keyNvId;

  // set status based on policy
  status = ZDSecMgrExtAddrLookup( extAddr, &ami );

  if ( status == ZSuccess )
  {
    // get the address NV ID
    if ( ZDSecMgrMasterKeyLookup( ami, &keyNvId ) == ZSuccess )
    {
      // overwrite old key in NV
      osal_nv_write( keyNvId, osal_offsetof(ZDSecMgrMasterKeyData_t, key),
                     SEC_KEY_LEN, key );
    }
    else
    {
      // store new key -- NULL will zero key
      status = ZDSecMgrMasterKeyStore( ami, key );
    }
  }

  return status;
}

uint8 ZDSecMgrAppKeyType = KEY_TYPE_APP_LINK;    // Set the default key type
                                                 // to KEY_TYPE_APP_LINK since
                                                 // only specific requirement
                                                 // right now comes from SE profile

ZStatus_t ZDSecMgrAppKeyGet( uint16  initNwkAddr,
                             uint8*  initExtAddr,
                             uint16  partNwkAddr,
                             uint8*  partExtAddr,
                             uint8** key,
                             uint8*  keyType )
{
  // Intentionally unreferenced parameters
  (void)initNwkAddr;
  (void)initExtAddr;
  (void)partNwkAddr;
  (void)partExtAddr;

  SSP_GetTrueRand( SEC_KEY_LEN, *key );

  *keyType = ZDSecMgrAppKeyType;

  return ZSuccess;
}

void ZDSecMgrAppKeyReq( ZDO_RequestKeyInd_t* ind )
{
  APSME_TransportKeyReq_t req;
  uint8                   initExtAddr[Z_EXTADDR_LEN];
  uint16                  partNwkAddr;
  uint8                   key[SEC_KEY_LEN];


  // validate initiator and partner
  if ( ( APSME_LookupNwkAddr( ind->partExtAddr, &partNwkAddr ) == TRUE ) &&
       ( APSME_LookupExtAddr( ind->srcAddr, initExtAddr ) == TRUE      )   )
  {
    // point the key to some memory
    req.key = key;

    // get an APP key - option APP (MASTER or LINK) key
    if ( ZDSecMgrAppKeyGet( ind->srcAddr,
                            initExtAddr,
                            partNwkAddr,
                            ind->partExtAddr,
                            &req.key,
                            &req.keyType ) == ZSuccess )
    {
      // always secure
      req.nwkSecure = TRUE;
      req.apsSecure = TRUE;
      req.tunnel    = NULL;

      // send key to initiator device
      req.dstAddr   = ind->srcAddr;
      req.extAddr   = ind->partExtAddr;
      req.initiator = TRUE;
      APSME_TransportKeyReq( &req );

      // send key to partner device
      req.dstAddr   = partNwkAddr;
      req.extAddr   = initExtAddr;
      req.initiator = FALSE;

      APSME_TransportKeyReq( &req );

      // clear copy of key in RAM
      osal_memset( key, 0x00, SEC_KEY_LEN);

    }
  }
}

ZStatus_t ZDSecMgrEstablishKey( ZDSecMgrDevice_t* device )
{
  ZStatus_t               status;
  APSME_EstablishKeyReq_t req;


  req.respExtAddr = device->extAddr;
  req.method      = APSME_SKKE_METHOD;

  if ( device->parentAddr == NLME_GetShortAddr() )
  {
    req.dstAddr   = device->nwkAddr;
    //devtag.0604.todo - remove obsolete
    req.apsSecure = FALSE;
    req.nwkSecure = FALSE;
  }
  else
  {
    req.dstAddr   = device->parentAddr;
    //devtag.0604.todo - remove obsolete
    req.apsSecure = TRUE;
    req.nwkSecure = TRUE;
  }

  status = APSME_EstablishKeyReq( &req );

  return status;
}

ZStatus_t ZDSecMgrSendMasterKey( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;
  APSME_TransportKeyReq_t req;
  uint16 keyNvId;
  uint8 masterKey[SEC_KEY_LEN];


  req.keyType = KEY_TYPE_TC_MASTER;
  req.extAddr = device->extAddr;
  req.tunnel  = NULL;

  if ( ZDSecMgrMasterKeyLookup( device->ctrl->entry->ami, &keyNvId ) == ZSuccess )
  {
    osal_nv_read( keyNvId, osal_offsetof(ZDSecMgrMasterKeyData_t, key),
                  SEC_KEY_LEN, masterKey );
  }
  else
  {
    // in case read from NV fails
    osal_memset( masterKey, 0x00, SEC_KEY_LEN);
  }

  req.key = masterKey;

  //check if using secure hop to to parent
  if ( device->parentAddr != NLME_GetShortAddr() )
  {
    //send to parent with security
    req.dstAddr   = device->parentAddr;
    req.nwkSecure = TRUE;
    req.apsSecure = TRUE;
  }
  else
  {
    //direct with no security
    req.dstAddr   = device->nwkAddr;
    req.nwkSecure = FALSE;
    req.apsSecure = FALSE;
  }

  status = APSME_TransportKeyReq( &req );

  // clear copy of key in RAM
  osal_memset( masterKey, 0x00, SEC_KEY_LEN);

  return status;
}

ZStatus_t ZDSecMgrSendNwkKey( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;
  APSME_TransportKeyReq_t req;
  APSDE_FrameTunnel_t tunnel;
  nwkKeyDesc tmpKey;

  req.dstAddr   = device->nwkAddr;
  req.extAddr   = device->extAddr;

  if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
  {
    req.keyType   = KEY_TYPE_NWK_HIGH;
  }
  else
  {
    req.keyType   = KEY_TYPE_NWK;
  }

  // get the Active Key into a local variable
  if( NLME_ReadNwkKeyInfo( 0, sizeof(tmpKey), &tmpKey,
                           ZCD_NV_NWK_ACTIVE_KEY_INFO ) != SUCCESS )
  {
    // set key data to all 0s if NV read fails
    osal_memset(&tmpKey, 0x00, sizeof(tmpKey));
  }

  if ( (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH)
      || (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD) )
  {
    // set values
    req.keySeqNum = tmpKey.keySeqNum;
    req.key       = tmpKey.key;

    //devtag.pro.security.todo - make sure that if there is no link key the NWK
    //key isn't used to secure the frame at the APS layer -- since the receiving
    //device may not have a NWK key yet
    req.apsSecure = TRUE;

    // check if using secure hop to to parent
    if ( device->parentAddr == NLME_GetShortAddr() )
    {
      req.nwkSecure = FALSE;
      req.tunnel    = NULL;
    }
    else
    {
      req.nwkSecure   = TRUE;
      req.tunnel      = &tunnel;
      req.tunnel->tna = device->parentAddr;
      req.tunnel->dea = device->extAddr;
    }
  }
  else
  {
    // default values
    //devtag.0604.verify
    req.nwkSecure = TRUE;
    req.apsSecure = FALSE;
    req.tunnel    = NULL;

    if ( device->parentAddr != NLME_GetShortAddr() )
    {
      req.dstAddr = device->parentAddr;
    }

    // special cases
    //devtag.0604.todo - modify to preconfig flag
    if ( device->secure == FALSE )
    {
      req.keySeqNum = tmpKey.keySeqNum;
      req.key       = tmpKey.key;

      // check if using secure hop to to parent
      if ( device->parentAddr == NLME_GetShortAddr() )
      {
        req.nwkSecure = FALSE;
      }
    }
    else
    {
      req.key       = NULL;
      req.keySeqNum = 0;
    }
  }

  status = APSME_TransportKeyReq( &req );

  // clear copy of key in RAM before return
  osal_memset( &tmpKey, 0x00, sizeof(nwkKeyDesc) );

  return status;
}

void ZDSecMgrDeviceEntryRemove( ZDSecMgrEntry_t* entry )
{
  // terminate device control
  if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
  {
    ZDSecMgrCtrlTerm( entry );
  }

  // remove device from entry data
  ZDSecMgrEntryFree( entry );

}

ZStatus_t ZDSecMgrDeviceRemoveByExtAddr( uint8 *pAddr )
{
  ZDSecMgrEntry_t *pEntry;
  uint8           retValue;

  retValue = (uint8)ZDSecMgrEntryLookupExt( pAddr, &pEntry );

  if( retValue == ZSuccess )
  {
    ZDSecMgrDeviceEntryRemove( pEntry );
  }

  return retValue;
}

void ZDSecMgrAddrMgrUpdate( uint16 ami, uint16 nwkAddr )
{
  AddrMgrEntry_t entry;

  // get the ami data
  entry.user  = ADDRMGR_USER_SECURITY;
  entry.index = ami;

  AddrMgrEntryGet( &entry );

  // check if NWK address is same
  if ( entry.nwkAddr != nwkAddr )
  {
    // update NWK address
    entry.nwkAddr = nwkAddr;

    AddrMgrEntryUpdate( &entry );
  }
}

ZStatus_t ZDSecMgrDeviceEntryAdd( ZDSecMgrDevice_t* device, uint16 ami )
{
  ZStatus_t        status;
  ZDSecMgrEntry_t* entry;

  // initialize as unknown until completion
  status = ZNwkUnknownDevice;

  device->ctrl = NULL;

  // make sure not already registered
  if ( ZDSecMgrEntryLookup( device->nwkAddr, &entry ) == ZSuccess )
  {
    // verify that address index is same
    if ( entry->ami != ami )
    {
      // remove conflicting entry
      ZDSecMgrDeviceEntryRemove( entry );

      if ( ZDSecMgrEntryLookupAMI( ami, &entry ) == ZSuccess )
      {
        // update NWK address
        ZDSecMgrAddrMgrUpdate( ami, device->nwkAddr );
      }
    }
  }
  else if ( ZDSecMgrEntryLookupAMI( ami, &entry ) == ZSuccess )
  {
    // update NWK address
    ZDSecMgrAddrMgrUpdate( ami, device->nwkAddr );
  }

  // check if a new entry needs to be created
  if ( entry == NULL )
  {
    // get new entry
    if ( ZDSecMgrEntryNew( &entry ) == ZSuccess )
    {
      // reset entry lkd

      // finish setting up entry
      entry->ami = ami;

      // update NWK address
      ZDSecMgrAddrMgrUpdate( ami, device->nwkAddr );

      // enter new device into device control
      if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
      {
        status = ZDSecMgrCtrlAdd( device, entry );
      }
      else
      {
        status = ZSuccess;
      }
    }
  }
  else
  {
    // reset entry lkd

    // reset entry in entry control
    if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
    {
      status = ZDSecMgrCtrlReset( device, entry );
    }
    else
    {
      status = ZSuccess;
    }
  }

  return status;
}

void ZDSecMgrDeviceCtrlHandler( ZDSecMgrDevice_t* device )
{
  uint8 state;
  uint8 cntr;

  state = device->ctrl->state;
  cntr  = ZDSECMGR_CTRL_BASE_CNTR;

  switch ( state )
  {
    case ZDSECMGR_CTRL_TK_MASTER:
      if ( ZDSecMgrSendMasterKey( device ) == ZSuccess )
      {
        state = ZDSECMGR_CTRL_SKKE_INIT;
        cntr  = ZDSECMGR_CTRL_SKKE_INIT_CNTR;
      }
      break;

    case ZDSECMGR_CTRL_SKKE_INIT:
      if ( ZDSecMgrEstablishKey( device ) == ZSuccess )
      {
        state = ZDSECMGR_CTRL_SKKE_WAIT;
      }
      break;

    case ZDSECMGR_CTRL_SKKE_WAIT:
      // continue to wait for SKA control timeout
      break;

    case ZDSECMGR_CTRL_TK_NWK:
      if ( ZDSecMgrSendNwkKey( device ) == ZSuccess )
      {
        state = ZDSECMGR_CTRL_NONE;
      }
      break;

    default:
      state = ZDSECMGR_CTRL_NONE;
      break;
  }

  if ( state != ZDSECMGR_CTRL_NONE )
  {
    device->ctrl->state = state;
    device->ctrl->cntr  = cntr;

    osal_start_timerEx(ZDAppTaskID, ZDO_SECMGR_EVENT, 100 );
  }
  else
  {
    ZDSecMgrCtrlRelease( device->ctrl );
  }
}

void ZDSecMgrDeviceCtrlSetup( ZDSecMgrDevice_t* device )
{
  if ( device->ctrl != NULL )
  {
    if ( device->secure == FALSE )
    {
      // send the master key data to the joining device
      device->ctrl->state = ZDSECMGR_CTRL_TK_MASTER;
    }
    else
    {
      // start SKKE
      device->ctrl->state = ZDSECMGR_CTRL_SKKE_INIT;
    }

    ZDSecMgrDeviceCtrlHandler( device );
  }
}

void ZDSecMgrDeviceCtrlUpdate( uint8* extAddr, uint8 state )
{
  ZDSecMgrEntry_t* entry;
  ZDSecMgrCtrl_t*  ctrl;

  // lookup device entry data
  (void)ZDSecMgrEntryLookupExt( extAddr, &entry );

  if ( entry != NULL )
  {
    // lookup device control data
    ZDSecMgrCtrlLookup( entry, &ctrl );

    // make sure control data is valid
    if ( ctrl != NULL )
    {
      // possible state transitions
      if ( ctrl->state == ZDSECMGR_CTRL_SKKE_WAIT )
      {
        if ( state == ZDSECMGR_CTRL_SKKE_DONE )
        {
          // send the network key
          ctrl->state = ZDSECMGR_CTRL_TK_NWK;
          ctrl->cntr  = ZDSECMGR_CTRL_TK_NWK_CNTR;
        }
        else if ( state == ZDSECMGR_CTRL_SKKE_FAIL )
        {
          // force default timeout in order to cleanup control logic
          ctrl->state = ZDSECMGR_CTRL_SKKE_FAIL;
          ctrl->cntr  = ZDSECMGR_CTRL_BASE_CNTR;
        }
      }
      // timer should be active
    }
  }
}

void APSME_SKA_TimerExpired( uint8 initiator, uint8* partExtAddr );
void APSME_SKA_TimerExpired( uint8 initiator, uint8* partExtAddr )
{
  if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
  {
    if ( initiator == TRUE )
    {
      ZDSecMgrDeviceCtrlUpdate( partExtAddr, ZDSECMGR_CTRL_SKKE_FAIL );
    }
  }
}


void ZDSecMgrDeviceRemove( ZDSecMgrDevice_t* device )
{
  APSME_RemoveDeviceReq_t remDevReq;
  NLME_LeaveReq_t         leaveReq;
  associated_devices_t*   assoc;

  // check if parent, remove the device
  if ( device->parentAddr == NLME_GetShortAddr() )
  {
    // this is the parent of the device
    leaveReq.extAddr        = device->extAddr;
    leaveReq.removeChildren = FALSE;
    leaveReq.rejoin         = FALSE;

    // find child association
    assoc = AssocGetWithExt( device->extAddr );

    if ( ( assoc != NULL                            ) &&
         ( assoc->nodeRelation >= CHILD_RFD         ) &&
         ( assoc->nodeRelation <= CHILD_FFD_RX_IDLE )    )
    {
      // check if associated device is authenticated
      if ( assoc->devStatus & DEV_SEC_AUTH_STATUS )
      {
        leaveReq.silent = FALSE;
      }
      else
      {
        leaveReq.silent = TRUE;
      }

      NLME_LeaveReq( &leaveReq );
    }
  }
  else
  {
    // this is not the parent of the device
    remDevReq.parentAddr   = device->parentAddr;
    remDevReq.childExtAddr = device->extAddr;

    APSME_RemoveDeviceReq( &remDevReq );
  }
}


ZStatus_t ZDSecMgrDeviceValidateSKKE( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;
  uint16 ami;
  uint16 keyNvId;

  // get EXT address
  status = ZDSecMgrExtAddrLookup( device->extAddr, &ami );

  if ( status == ZSuccess )
  {
    // get MASTER key
    status = ZDSecMgrMasterKeyLookup( ami, &keyNvId );

    if ( status == ZSuccess )
    {
      status = ZDSecMgrDeviceEntryAdd( device, ami );
    }
  }

  return status;
}


ZStatus_t ZDSecMgrDeviceValidateRM( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;

  status = ZSuccess;

  (void)device;  // Intentionally unreferenced parameter

  if ( zgSecurePermitJoin == FALSE )
  {
    status = ZNwkUnknownDevice;
  }



#if 0  // Taken out because the following functionality is only used for test
       // purpose. A more efficient (above) way is used. It can be put
       // back in if customers request for a white/black list feature.
       // ZDSecMgrStoredDeviceList[] is defined in ZDSecMgr.c

  // The following code processes the device black list (stored device list)
  // If the joining device is not part of the forbidden device list
  // Return ZSuccess. Otherwise, return ZNwkUnknownDevice. The trust center
  // will send Remove-device and ban the device from joining.

  uint8     index;
  uint8*    restricted;

  // Look through the stored device list - used for restricted devices
  for ( index = 0; index < ZDSECMGR_STORED_DEVICES; index++ )
  {
    restricted = ZDSecMgrStoredDeviceList[index];

    if ( AddrMgrExtAddrEqual( restricted, device->extAddr )  == TRUE )
    {
      // return as unknown device in regards to validation
      status = ZNwkUnknownDevice;

      // break from loop
      index = ZDSECMGR_STORED_DEVICES;
    }
  }

#endif

  return status;
}


//devtag.pro.security
ZStatus_t ZDSecMgrDeviceValidateCM( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;
  uint16    ami;
  uint8     key[SEC_KEY_LEN];

  // implement EXT address and MASTER key policy here -- the total number of
  // Security Manager entries should never exceed the number of EXT addresses
  // and MASTER keys available

  // set status based on policy
  //status = ZNwkUnknownDevice;

  // set status based on policy
  status = ZSuccess; // ZNwkUnknownDevice;

  // get key based on policy
  osal_memcpy( key, ZDSecMgrTCMasterKey, SEC_KEY_LEN);

  // if policy, store new EXT address
  status = ZDSecMgrAddrStore( device->nwkAddr, device->extAddr, &ami );

  // set the key
  ZDSecMgrMasterKeyLoad( device->extAddr, key );

  // if EXT address and MASTER key available -- add device
  if ( status == ZSuccess )
  {
    // add device to internal data - with control
    status = ZDSecMgrDeviceEntryAdd( device, ami );
  }

  // remove copy of key in RAM
  osal_memset( key, 0x00, SEC_KEY_LEN );

  return status;
}


ZStatus_t ZDSecMgrDeviceValidate( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;


  if ( ZDSecMgrPermitJoiningEnabled == TRUE )
  {
    // device may be joining with a secure flag but it is ultimately the Trust
    // Center that decides -- check if expected pre configured device --
    // override settings
    if ( zgPreConfigKeys == TRUE )
    {
      device->secure = TRUE;
    }
    else
    {
      device->secure = FALSE;
    }

    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    {
      status = ZDSecMgrDeviceValidateCM( device );
    }
    else // ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_RESIDENTIAL )
    {
      status = ZDSecMgrDeviceValidateRM( device );
    }
  }
  else
  {
    status = ZNwkUnknownDevice;
  }

  return status;
}


ZStatus_t ZDSecMgrDeviceJoin( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;
  uint16    ami;

  // attempt to validate device
  status = ZDSecMgrDeviceValidate( device );

  if ( status == ZSuccess )
  {
    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    {
      ZDSecMgrDeviceCtrlSetup( device );
    }
    else // ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_RESIDENTIAL )
    {
      // Add the device to the address manager
      ZDSecMgrAddrStore( device->nwkAddr, device->extAddr, &ami );
      //send the nwk key data to the joining device
      status = ZDSecMgrSendNwkKey( device );
    }
  }
  else
  {
    // not allowed, remove the device
    ZDSecMgrDeviceRemove( device );
  }

  return status;
}


ZStatus_t ZDSecMgrDeviceJoinDirect( ZDSecMgrDevice_t* device )
{
  ZStatus_t status;

  status = ZDSecMgrDeviceJoin( device );

  if ( status == ZSuccess )
  {
    // set association status to authenticated
    ZDSecMgrAssocDeviceAuth( AssocGetWithShort( device->nwkAddr ) );
  }

  return status;
}


ZStatus_t ZDSecMgrDeviceJoinFwd( ZDSecMgrDevice_t* device )
{
  ZStatus_t               status;
  APSME_UpdateDeviceReq_t req;

  // forward any joining device to the Trust Center -- the Trust Center will
  // decide if the device is allowed to join
  status = ZSuccess;

  // forward authorization to the Trust Center
  req.dstAddr    = APSME_TRUSTCENTER_NWKADDR;
  req.devAddr    = device->nwkAddr;
  req.devExtAddr = device->extAddr;

  // set security status, option for router to reject if policy set
  if ( (device->devStatus & DEV_HIGH_SEC_STATUS) )
  {
    if ( device->devStatus & DEV_REJOIN_STATUS )
    {
      if ( device->secure == TRUE )
      {
        req.status = APSME_UD_HIGH_SECURED_REJOIN;
      }
      else
      {
        req.status = APSME_UD_HIGH_UNSECURED_REJOIN;
      }
    }
    else
    {
      req.status = APSME_UD_HIGH_UNSECURED_JOIN;
    }
  }
  else
  {
    if ( device->devStatus & DEV_REJOIN_STATUS )
    {
      if ( device->secure == TRUE )
      {
        req.status = APSME_UD_STANDARD_SECURED_REJOIN;
      }
      else
      {
        req.status = APSME_UD_STANDARD_UNSECURED_REJOIN;
      }
    }
    else
    {
      req.status = APSME_UD_STANDARD_UNSECURED_JOIN;
    }
  }

  if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
  {
    req.apsSecure = TRUE;
  }
  else
  {
    req.apsSecure = FALSE;
  }

  // send and APSME_UPDATE_DEVICE request to the trust center
  status = APSME_UpdateDeviceReq( &req );

  return status;
}


ZStatus_t ZDSecMgrDeviceNew( ZDSecMgrDevice_t* joiner )
{
  ZStatus_t status;

  if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
  {
    // try to join this device
    status = ZDSecMgrDeviceJoinDirect( joiner );
  }
  else
  {
    status = ZDSecMgrDeviceJoinFwd( joiner );
  }

  return status;
}


void ZDSecMgrAssocDeviceAuth( associated_devices_t* assoc )
{
  if ( assoc != NULL )
  {
    assoc->devStatus |= DEV_SEC_AUTH_STATUS;
  }
}


void ZDSecMgrAuthInitiate( uint8* responder )
{
  APSME_AuthenticateReq_t req;


  // make sure NWK address is available
  if ( APSME_LookupNwkAddr( responder, &req.nwkAddr ) )
  {
    // set request fields
    req.extAddr   = responder;
    req.action    = APSME_EA_INITIATE;
    req.challenge = NULL;

    // start EA processing
    APSME_AuthenticateReq( &req );
  }
}

void ZDSecMgrAuthNwkKey()
{
  if ( devState == DEV_END_DEVICE_UNAUTH )
  {
    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    {
      uint8 parent[Z_EXTADDR_LEN];

      // get parent's EXT address
      NLME_GetCoordExtAddr( parent );

      // begin entity authentication with parent
      ZDSecMgrAuthInitiate( parent );
    }
    else
    {
      // inform ZDO that device has been authenticated
      osal_set_event ( ZDAppTaskID, ZDO_DEVICE_AUTH );
    }
  }
}

#if ( ADDRMGR_CALLBACK_ENABLED == 1 )
void ZDSecMgrAddrMgrCB( uint8 update, AddrMgrEntry_t* newEntry, AddrMgrEntry_t* oldEntry );
void ZDSecMgrAddrMgrCB( uint8           update,
                        AddrMgrEntry_t* newEntry,
                        AddrMgrEntry_t* oldEntry )
{
  (void)update;
  (void)newEntry;
  (void)oldEntry;
}
#endif // ( ADDRMGR_CALLBACK_ENABLED == 1 )

void ZDSecMgrInit(uint8 state)
{
  if ( (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH)
      || (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD) )
  {
    // initialize sub modules
    ZDSecMgrEntryInit(state);

    if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
    {
      ZDSecMgrCtrlInit();
    }

    // register with Address Manager
#if ( ADDRMGR_CALLBACK_ENABLED == 1 )
    AddrMgrRegister( ADDRMGR_REG_SECURITY, ZDSecMgrAddrMgrCB );
#endif
  }

  if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
  {
    // configure SKA slot data
    APSME_SKA_SlotInit( ZDSECMGR_SKA_SLOT_MAX );
  }

  if ( ZG_SECURE_ENABLED )
  {
    if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
    {
      // setup joining permissions
      ZDSecMgrPermitJoiningEnabled = TRUE;
      ZDSecMgrPermitJoiningTimed   = FALSE;
    }
  }

  // configure security based on security mode and type of device
  ZDSecMgrConfig();
}


void ZDSecMgrConfig( void )
{
  if ( ZG_SECURE_ENABLED )
  {
    SSP_Init();

    if ( (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH)
        || (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD) )
    {
      if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
      {
        // COMMERCIAL MODE - COORDINATOR DEVICE
        APSME_SecurityCM_CD();
      }
      else if ( ZSTACK_ROUTER_BUILD )
      {
        // COMMERCIAL MODE - ROUTER DEVICE
        APSME_SecurityCM_RD();
      }
      else
      {
        // COMMERCIAL MODE - END DEVICE
        APSME_SecurityCM_ED();
      }
    }
    else // ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_RESIDENTIAL )
    {
      if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
      {
        // RESIDENTIAL MODE - COORDINATOR DEVICE
        APSME_SecurityRM_CD();
      }
      else if ( ZSTACK_ROUTER_BUILD )
      {
        // RESIDENTIAL MODE - ROUTER DEVICE
        APSME_SecurityRM_RD();
      }
      else
      {
        // RESIDENTIAL MODE - END DEVICE
        APSME_SecurityRM_ED();
      }
    }
  }
  else
  {
    // NO SECURITY
    APSME_SecurityNM();
  }
}


uint8 ZDSecMgrPermitJoining( uint8 duration )
{
  uint8 accept;

  ZDSecMgrPermitJoiningTimed = FALSE;

  if ( duration > 0 )
  {
    ZDSecMgrPermitJoiningEnabled = TRUE;

    if ( duration != 0xFF )
    {
      ZDSecMgrPermitJoiningTimed = TRUE;
    }
  }
  else
  {
    ZDSecMgrPermitJoiningEnabled = FALSE;
  }

  accept = TRUE;

  return accept;
}


void ZDSecMgrPermitJoiningTimeout( void )
{
  if ( ZDSecMgrPermitJoiningTimed == TRUE )
  {
    ZDSecMgrPermitJoiningEnabled = FALSE;
    ZDSecMgrPermitJoiningTimed   = FALSE;
  }
}

uint8 ZDSecMgrNewDeviceEvent( void )
{
  uint8                 found;
  ZDSecMgrDevice_t      device;
  AddrMgrEntry_t        addrEntry;
  associated_devices_t* assoc;
  ZStatus_t             status;

  // initialize return results
  found = FALSE;

  // look for device in the security init state
  assoc = AssocMatchDeviceStatus( DEV_SEC_INIT_STATUS );

  if ( assoc != NULL )
  {
    // device found
    found = TRUE;

    // check for preconfigured security
    if ( zgPreConfigKeys == TRUE )
    {
      // set association status to authenticated
      ZDSecMgrAssocDeviceAuth( assoc );
    }

    // set up device info
    addrEntry.user  = ADDRMGR_USER_DEFAULT;
    addrEntry.index = assoc->addrIdx;
    AddrMgrEntryGet( &addrEntry );

    device.nwkAddr    = assoc->shortAddr;
    device.extAddr    = addrEntry.extAddr;
    device.parentAddr = NLME_GetShortAddr();
    device.secure     = FALSE;
    device.devStatus  = assoc->devStatus;

    // process new device
    status = ZDSecMgrDeviceNew( &device );

    if ( status == ZSuccess )
    {
      assoc->devStatus &= ~DEV_SEC_INIT_STATUS;
    }
    else if ( status == ZNwkUnknownDevice )
    {
      AssocRemove( addrEntry.extAddr );
    }
  }

  return found;
}

void ZDSecMgrEvent( void )
{
  uint8            action;
  uint8            restart;
  uint16           index;
  AddrMgrEntry_t   entry;
  ZDSecMgrDevice_t device;

  // verify data is available
  if ( ZDSecMgrCtrlData != NULL )
  {
    action  = FALSE;
    restart = FALSE;

    // update all the counters
    for ( index = 0; index < ZDSECMGR_ENTRY_MAX; index++ )
    {
      if ( ZDSecMgrCtrlData[index].state !=  ZDSECMGR_CTRL_NONE )
      {
        if ( ZDSecMgrCtrlData[index].cntr != 0 )
        {
          ZDSecMgrCtrlData[index].cntr--;
        }

        if ( ( action == FALSE ) && ( ZDSecMgrCtrlData[index].cntr == 0 ) )
        {
          action = TRUE;

          // update from control data
          device.parentAddr = ZDSecMgrCtrlData[index].parentAddr;
          device.secure     = ZDSecMgrCtrlData[index].secure;
          device.ctrl       = &ZDSecMgrCtrlData[index];

          // set the user and address index
          entry.user  = ADDRMGR_USER_SECURITY;
          entry.index = ZDSecMgrCtrlData[index].entry->ami;

          // get the address data
          AddrMgrEntryGet( &entry );

          // set device address data
          device.nwkAddr = entry.nwkAddr;
          device.extAddr = entry.extAddr;

          // update from entry data
          ZDSecMgrDeviceCtrlHandler( &device );
        }
        else
        {
          restart = TRUE;
        }
      }
    }

    // check for timer restart
    if ( restart == TRUE )
    {
      osal_start_timerEx(ZDAppTaskID, ZDO_SECMGR_EVENT, 100 );
    }
  }
}


void ZDSecMgrEstablishKeyCfm( ZDO_EstablishKeyCfm_t* cfm )
{
  // send the NWK key
  if ( ( ZG_BUILD_COORDINATOR_TYPE ) && ( ZG_DEVICE_COORDINATOR_TYPE ) )
  {
    // update control for specified EXT address
    ZDSecMgrDeviceCtrlUpdate( cfm->partExtAddr, ZDSECMGR_CTRL_SKKE_DONE );
  }
  else
  {
    // this should be done when receiving the NWK key
    // if devState ==
    //if ( devState == DEV_END_DEVICE_UNAUTH )
        //osal_set_event( ZDAppTaskID, ZDO_DEVICE_AUTH );

    // if not in joining state -- this should trigger an event for an
    // end point that requested SKKE
    // if ( devState == DEV_END_DEVICE )
   //       devState == DEV_ROUTER;

  }
}


uint8 ZDSecMgrTCExtAddrCheck( uint8* extAddr )
{
  uint8  match;
  uint8  lookup[Z_EXTADDR_LEN];

  match = FALSE;

  if ( AddrMgrExtAddrLookup( APSME_TRUSTCENTER_NWKADDR, lookup ) )
  {
    match = AddrMgrExtAddrEqual( lookup, extAddr );
  }

  return match;
}


void ZDSecMgrTCDataLoad( uint8* extAddr )
{
  uint16 ami;
  uint16 keyNvId;
  uint8 masterKey[SEC_KEY_LEN];
  AddrMgrEntry_t entry;

  // lookup using TC short address
  entry.user    = ADDRMGR_USER_DEFAULT;
  entry.nwkAddr = zgTrustCenterAddr;

  // Verify if TC address has been added to Address Manager
  if ( AddrMgrEntryLookupNwk( &entry ) != TRUE )
  {
    if ( ZDSecMgrAddrStore( zgTrustCenterAddr, extAddr, &ami ) == ZSuccess )
    {
      // if preconfigured load key
      if ( zgPreConfigKeys == TRUE )
      {
        if ( ZDSecMgrMasterKeyLookup( ami, &keyNvId ) != ZSuccess )
        {
          // temporary copy
          osal_memcpy( masterKey, ZDSecMgrTCMasterKey, SEC_KEY_LEN);

          ZDSecMgrMasterKeyStore( ami, masterKey );

          // remove copy of key in RAM
          osal_memset( masterKey, 0x00, SEC_KEY_LEN );
        }
      }
    }
  }
}


void ZDSecMgrEstablishKeyInd( ZDO_EstablishKeyInd_t* ind )
{
  ZDSecMgrDevice_t        device;
  APSME_EstablishKeyRsp_t rsp;


  // load Trust Center data if needed
  ZDSecMgrTCDataLoad( ind->initExtAddr );

  if ( ZDSecMgrTCExtAddrCheck( ind->initExtAddr ) )
  {
    //IF (ind->srcAddr == APSME_TRUSTCENTER_NWKADDR)
    //OR
    //!ZDSecMgrTCAuthenticated
    //devtag.0604.critical
        //how is the parentAddr used here

    // initial SKKE from Trust Center via parent
    device.nwkAddr    = APSME_TRUSTCENTER_NWKADDR;
    device.parentAddr = ind->srcAddr;
  }
  else
  {
    // Trust Center direct or E2E SKKE
    device.nwkAddr    = ind->srcAddr;
    device.parentAddr = INVALID_NODE_ADDR;
  }

  device.extAddr = ind->initExtAddr;
  //devtag.pro.security.0724.todo - verify usage
  device.secure  = ind->nwkSecure;

  // validate device for SKKE
  if ( ZDSecMgrDeviceValidateSKKE( &device ) == ZSuccess )
  {
    rsp.accept = TRUE;
  }
  else
  {
    rsp.accept = FALSE;
  }

  rsp.dstAddr     = ind->srcAddr;
  rsp.initExtAddr = &ind->initExtAddr[0];
  //devtag.0604.todo - remove obsolete
  rsp.apsSecure   = ind->apsSecure;
  rsp.nwkSecure   = ind->nwkSecure;

  APSME_EstablishKeyRsp( &rsp );
}

//devtag.pro.security
#if 0
void ZDSecMgrEstablishKeyInd( ZDO_EstablishKeyInd_t* ind )
{
  ZDSecMgrDevice_t        device;
  APSME_EstablishKeyRsp_t rsp;


  device.extAddr = ind->initExtAddr;
  device.secure  = ind->secure;

  if ( ind->secure == FALSE )
  {
    // SKKE from Trust Center is not secured between child and parent
    device.nwkAddr    = APSME_TRUSTCENTER_NWKADDR;
    device.parentAddr = ind->srcAddr;
  }
  else
  {
    // SKKE from initiator should be secured
    device.nwkAddr    = ind->srcAddr;
    device.parentAddr = INVALID_NODE_ADDR;
  }

  rsp.dstAddr     = ind->srcAddr;
  rsp.initExtAddr = &ind->initExtAddr[0];
  rsp.secure      = ind->secure;

  // validate device for SKKE
  if ( ZDSecMgrDeviceValidateSKKE( &device ) == ZSuccess )
  {
    rsp.accept = TRUE;
  }
  else
  {
    rsp.accept = FALSE;
  }

  APSME_EstablishKeyRsp( &rsp );
}
#endif

void ZDSecMgrTransportKeyInd( ZDO_TransportKeyInd_t* ind )
{
  uint8 index;
  uint8 zgPreConfigKey[SEC_KEY_LEN];

  // load Trust Center data if needed
  ZDSecMgrTCDataLoad( ind->srcExtAddr );

  if ( ind->keyType == KEY_TYPE_TC_MASTER )
  {
    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    //ZDSecMgrTCMasterKey( ind );
    {
      if ( zgPreConfigKeys != TRUE )
      {
        // devtag.pro.security.todo - check if Trust Center address is configured and correct
        ZDSecMgrMasterKeyLoad( ind->srcExtAddr, ind->key );
      }
      else
      {
        // error condition - reject key
      }
    }
  }
  else if ( ( ind->keyType == KEY_TYPE_NWK      ) ||
            ( ind->keyType == 6                 ) ||
            ( ind->keyType == KEY_TYPE_NWK_HIGH )    )
  {
    // 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 )
  {
    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    {
      // This should not happen because TCLK should not be Tx
    }
  }
  else if ( ind->keyType == KEY_TYPE_APP_MASTER )
  {
    if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
    {
      uint16           ami;
      AddrMgrEntry_t   entry;
      ZDSecMgrEntry_t* entryZD;

      ZDSecMgrExtAddrLookup( ind->srcExtAddr, &ami );

      if ( ind->initiator == TRUE )
      {
        // get the ami data
        entry.user  = ADDRMGR_USER_SECURITY;
        entry.index = ami;
        AddrMgrEntryGet( &entry );

        if ( entry.nwkAddr != INVALID_NODE_ADDR )
        {
          APSME_EstablishKeyReq_t req;
          ZDSecMgrMasterKeyLoad( ind->srcExtAddr, ind->key );

          ZDSecMgrEntryLookupAMI( ami, &entryZD );

          if ( entryZD == NULL )
          {
            // get new entry
            if ( ZDSecMgrEntryNew( &entryZD ) == ZSuccess )
            {
              // finish setting up entry
              entryZD->ami = ami;
            }
          }

          req.respExtAddr = ind->srcExtAddr;
          req.method      = APSME_SKKE_METHOD;
          req.dstAddr     = entry.nwkAddr;
          req.apsSecure   = FALSE;
          req.nwkSecure   = TRUE;
          APSME_EstablishKeyReq( &req );
        }
      }
      else
      {
        if ( ami == INVALID_NODE_ADDR )
        {
          // store new EXT address
          ZDSecMgrAddrStore( INVALID_NODE_ADDR, ind->srcExtAddr, &ami );
        }

        ZDSecMgrMasterKeyLoad( ind->srcExtAddr, ind->key );
      }
    }
  }
  else if ( ind->keyType == KEY_TYPE_APP_LINK )
  {
    if ( ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH ) ||
         ( 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
    }
  }
}

void ZDSecMgrUpdateDeviceInd( ZDO_UpdateDeviceInd_t* ind )
{
  ZDSecMgrDevice_t device;

  device.nwkAddr    = ind->devAddr;
  device.extAddr    = ind->devExtAddr;
  device.parentAddr = ind->srcAddr;

  //if ( ( ind->status == APSME_UD_SECURED_JOIN   ) ||
  //     ( ind->status == APSME_UD_UNSECURED_JOIN )   )
  //{
  //  if ( ind->status == APSME_UD_SECURED_JOIN )
  //  {
  //    device.secure = TRUE;
  //  }
  //  else
  //  {
  //    device.secure = FALSE;
  //  }

    // try to join this device
    ZDSecMgrDeviceJoin( &device );
  //}
}


void ZDSecMgrRemoveDeviceInd( ZDO_RemoveDeviceInd_t* ind )
{
  ZDSecMgrDevice_t device;

  // only accept from Trust Center
  if ( ind->srcAddr == APSME_TRUSTCENTER_NWKADDR )
  {
    // look up NWK address
    if ( APSME_LookupNwkAddr( ind->childExtAddr, &device.nwkAddr ) == TRUE )
    {
      device.parentAddr = NLME_GetShortAddr();
      device.extAddr    = ind->childExtAddr;

      // remove device
      ZDSecMgrDeviceRemove( &device );
    }
  }
}

void ZDSecMgrRequestKeyInd( ZDO_RequestKeyInd_t* ind )
{
  if ( ind->keyType == KEY_TYPE_NWK )
  {
  }
  else if ( ind->keyType == KEY_TYPE_APP_MASTER )
  {
    ZDSecMgrAppKeyReq( ind );
  }
  else if ( ind->keyType == KEY_TYPE_TC_LINK )
  {
  }
  //else ignore
}


void ZDSecMgrSwitchKeyInd( ZDO_SwitchKeyInd_t* ind )
{
  SSP_SwitchNwkKey( ind->keySeqNum );

  // Save if nv
  ZDApp_NVUpdate();
}

void ZDSecMgrAuthenticateInd( ZDO_AuthenticateInd_t* ind )
{
  APSME_AuthenticateReq_t req;
  AddrMgrEntry_t          entry;


  entry.user    = ADDRMGR_USER_SECURITY;
  entry.nwkAddr = ind->aps.initNwkAddr;
  AddrMgrExtAddrSet( entry.extAddr, ind->aps.initExtAddr );

  if ( AddrMgrEntryUpdate( &entry ) == TRUE )
  {
    // set request fields
    req.nwkAddr   = ind->aps.initNwkAddr;
    req.extAddr   = ind->aps.initExtAddr;
    req.action    = APSME_EA_ACCEPT;
    req.challenge = ind->aps.challenge;

    // start EA processing
    APSME_AuthenticateReq( &req );
  }
}


void ZDSecMgrAuthenticateCfm( ZDO_AuthenticateCfm_t* cfm )
{
  if ( cfm->aps.status == ZSuccess )
  {
    if ( ( cfm->aps.initiator == TRUE ) && ( devState == DEV_END_DEVICE_UNAUTH ) )
    {
      // inform ZDO that device has been authenticated
      osal_set_event ( ZDAppTaskID, ZDO_DEVICE_AUTH );
    }
  }
}

#if ( ZG_BUILD_COORDINATOR_TYPE )

ZStatus_t ZDSecMgrUpdateNwkKey( uint8* key, uint8 keySeqNum, uint16 dstAddr )
{
  ZStatus_t               status;
  APSME_TransportKeyReq_t req;

  // initialize common elements of local variables
  if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
  {
    req.keyType   = KEY_TYPE_NWK_HIGH;
  }
  else
  {
    req.keyType   = KEY_TYPE_NWK;
  }

  req.dstAddr   = dstAddr;
  req.keySeqNum = keySeqNum;
  req.key       = key;
  req.extAddr   = NULL;
  req.nwkSecure = TRUE;
  req.apsSecure = TRUE;
  req.tunnel    = NULL;

  if (( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH ) ||
      ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD ))
  {
    ZDSecMgrEntry_t*        entry;
    uint16                  index;
    AddrMgrEntry_t          addrEntry;

    addrEntry.user = ADDRMGR_USER_SECURITY;

    status = ZFailure;

    // verify data is available
    if ( ZDSecMgrEntries != NULL )
    {
      // find available entry
      for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
      {
        if ( ZDSecMgrEntries[index].ami != INVALID_NODE_ADDR )
        {
          // return successful result
          entry = &ZDSecMgrEntries[index];

          // get NWK address
          addrEntry.index = entry->ami;
          if ( AddrMgrEntryGet( &addrEntry ) == TRUE )
          {
            req.dstAddr = addrEntry.nwkAddr;
            req.extAddr = addrEntry.extAddr;
            status = APSME_TransportKeyReq( &req );
          }
        }
      }
    }
  }
  else // ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_RESIDENTIAL )
  {
    status = APSME_TransportKeyReq( &req );
  }

  SSP_UpdateNwkKey( key, keySeqNum );

  // Save if nv
  ZDApp_NVUpdate();

  return status;
}
#endif // ( ZG_BUILD_COORDINATOR_TYPE )

#if ( ZG_BUILD_COORDINATOR_TYPE )

ZStatus_t ZDSecMgrSwitchNwkKey( uint8 keySeqNum, uint16 dstAddr )
{
  ZStatus_t            status;
  APSME_SwitchKeyReq_t req;

  // initialize common elements of local variables
  req.dstAddr = dstAddr;
  req.keySeqNum = keySeqNum;

  if (( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH ) ||
      ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD ))
  {
    ZDSecMgrEntry_t*     entry;
    uint16               index;
    AddrMgrEntry_t       addrEntry;

    addrEntry.user = ADDRMGR_USER_SECURITY;

    status = ZFailure;

    // verify data is available
    if ( ZDSecMgrEntries != NULL )
    {
      // find available entry
      for ( index = 0; index < ZDSECMGR_ENTRY_MAX ; index++ )
      {
        if ( ZDSecMgrEntries[index].ami != INVALID_NODE_ADDR )
        {
          // return successful result
          entry = &ZDSecMgrEntries[index];

          // get NWK address
          addrEntry.index = entry->ami;

          if ( AddrMgrEntryGet( &addrEntry ) == TRUE )
          {
            req.dstAddr = addrEntry.nwkAddr;
            status = APSME_SwitchKeyReq( &req );
          }
        }
      }
    }
  }
  else // ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_RESIDENTIAL )
  {
    status = APSME_SwitchKeyReq( &req );
  }

  SSP_SwitchNwkKey( keySeqNum );

  // Save if nv
  ZDApp_NVUpdate();

  return status;
}
#endif // ( ZG_BUILD_COORDINATOR_TYPE )


ZStatus_t ZDSecMgrRequestAppKey( uint8 *partExtAddr )
{
  ZStatus_t status;
  APSME_RequestKeyReq_t req;

  req.dstAddr = 0;
  req.keyType = KEY_TYPE_APP_MASTER;

  req.partExtAddr = partExtAddr;
  status = APSME_RequestKeyReq( &req );

  return status;
}

#if ( ZG_BUILD_JOINING_TYPE )

ZStatus_t ZDSecMgrSetupPartner( uint16 partNwkAddr, uint8* partExtAddr )
{
  AddrMgrEntry_t entry;
  ZStatus_t      status;

  status = ZFailure;

  // update the address manager
  entry.user    = ADDRMGR_USER_SECURITY;
  entry.nwkAddr = partNwkAddr;
  AddrMgrExtAddrSet( entry.extAddr, partExtAddr );

  if ( AddrMgrEntryUpdate( &entry ) == TRUE )
  {
    status = ZSuccess;

    // check for address discovery
    if ( partNwkAddr == INVALID_NODE_ADDR )
    {
      status = ZDP_NwkAddrReq( partExtAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
    }
    else if ( !AddrMgrExtAddrValid( partExtAddr ) )
    {
      status = ZDP_IEEEAddrReq( partNwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
    }
  }

  return status;
}
#endif // ( ZG_BUILD_JOINING_TYPE )

#if ( ZG_BUILD_COORDINATOR_TYPE )

ZStatus_t ZDSecMgrAppKeyTypeSet( uint8 keyType )
{
  if ( keyType == KEY_TYPE_APP_LINK )
  {
    ZDSecMgrAppKeyType = KEY_TYPE_APP_LINK;
  }
  else
  {
    ZDSecMgrAppKeyType = KEY_TYPE_APP_MASTER;
  }

  return ZSuccess;
}
#endif


ZStatus_t ZDSecMgrMasterKeyGet( uint8* extAddr, uint16* pKeyNvId )
{
  ZStatus_t status;
  uint16 ami;

  // lookup entry for specified EXT address
  status = ZDSecMgrExtAddrLookup( extAddr, &ami );

  if ( status == ZSuccess )
  {
    ZDSecMgrMasterKeyLookup( ami, pKeyNvId );
  }
  else
  {
    *pKeyNvId = SEC_NO_KEY_NV_ID;
  }

  return status;
}


ZStatus_t ZDSecMgrLinkKeySet( uint8* extAddr, uint8* key )
{
  ZStatus_t status;
  ZDSecMgrEntry_t* entry;
  APSME_LinkKeyData_t *pApsLinkKey = NULL;
  uint16 Index;

  // lookup entry index for specified EXT address
  status = ZDSecMgrEntryLookupExtGetIndex( extAddr, &entry, &Index );

  if ( status == ZSuccess )
  {
    // point to NV item
    entry->keyNvId = ZCD_NV_APS_LINK_KEY_DATA_START + Index;

    pApsLinkKey = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

    if (pApsLinkKey != NULL)
    {
      // read the key form NV, keyNvId must be ZCD_NV_APS_LINK_KEY_DATA_START based
      osal_nv_read( entry->keyNvId, 0,
                   sizeof(APSME_LinkKeyData_t), pApsLinkKey );

      // set new values of the key
      osal_memcpy( pApsLinkKey->key, key, SEC_KEY_LEN );
      pApsLinkKey->rxFrmCntr = 0;
      pApsLinkKey->txFrmCntr = 0;

      osal_nv_write( entry->keyNvId, 0,
                    sizeof(APSME_LinkKeyData_t), pApsLinkKey );

      // clear copy of key in RAM
      osal_memset(pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t));

      osal_mem_free(pApsLinkKey);

      // set initial values for counters in RAM
      ApsLinkKeyFrmCntr[entry->keyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].txFrmCntr = 0;
      ApsLinkKeyFrmCntr[entry->keyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].rxFrmCntr = 0;
    }
  }

  return status;
}

ZStatus_t ZDSecMgrAuthenticationSet( uint8* extAddr, ZDSecMgr_Authentication_Option option )
{
  ZStatus_t        status;
  ZDSecMgrEntry_t* entry;


  // lookup entry index for specified EXT address
  status = ZDSecMgrEntryLookupExt( extAddr, &entry );

  if ( status == ZSuccess )
  {
    entry->authenticateOption = option;
  }

  return status;
}



uint8 ZDSecMgrAuthenticationCheck( uint16 shortAddr )
{
#if defined (TC_LINKKEY_JOIN)

  ZDSecMgrEntry_t* entry;
  uint8 extAddr[Z_EXTADDR_LEN];

  // If the local device is not the trust center, always return TRUE
  if ( NLME_GetShortAddr() != zgTrustCenterAddr )
  {
    return TRUE;
  }
  // Otherwise, check the authentication option
  else if ( AddrMgrExtAddrLookup( shortAddr, extAddr ) )
  {
    // lookup entry index for specified EXT address
    if ( ZDSecMgrEntryLookupExt( extAddr, &entry ) == ZSuccess )
    {
      if ( entry->authenticateOption != ZDSecMgr_Not_Authenticated )
      {
        return TRUE;
      }
      else
      {
        return FALSE;
      }
    }
  }
  return FALSE;

#else
  (void)shortAddr;  // Intentionally unreferenced parameter

  // For non AMI/SE Profile, perform no check and always return TRUE.
  return TRUE;

#endif // TC_LINKKEY_JOIN
}


ZStatus_t ZDSecMgrLinkKeyNVIdGet(uint8* extAddr, uint16 *pKeyNvId)
{
  ZStatus_t status;
  ZDSecMgrEntry_t* entry;

  // lookup entry index for specified NWK address
  status = ZDSecMgrEntryLookupExt( extAddr, &entry );

  if ( status == ZSuccess )
  {
    // return the index to the NV table
    *pKeyNvId = entry->keyNvId;
  }
  else
  {
    *pKeyNvId = SEC_NO_KEY_NV_ID;
  }

  return status;
}


uint8 ZDSecMgrIsLinkKeyValid(uint8* extAddr)
{
  APSME_LinkKeyData_t *pKeyData;
  uint16 apsLinkKeyNvId;
  uint8 nullKey[SEC_KEY_LEN];
  uint8 status = FALSE;

  // initialize default vealue to compare to
  osal_memset(nullKey, 0x00, SEC_KEY_LEN);

  // check for APS link NV ID
  APSME_LinkKeyNVIdGet( extAddr, &apsLinkKeyNvId );

  if (apsLinkKeyNvId != SEC_NO_KEY_NV_ID )
  {
    pKeyData = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

    if (pKeyData != NULL)
    {
      // retrieve key from NV
      if ( osal_nv_read( apsLinkKeyNvId, 0,
                        sizeof(APSME_LinkKeyData_t), pKeyData) == ZSUCCESS)
      {
        // if stored key is different than default value, then a key has been established
        if (!osal_memcmp(pKeyData, nullKey, SEC_KEY_LEN))
        {
          status = TRUE;
        }
      }

      // clear copy of key in RAM
      osal_memset(pKeyData, 0x00, sizeof(APSME_LinkKeyData_t));

      osal_mem_free(pKeyData);
    }
  }

  return status;
}


uint8 ZDSecMgrKeyFwdToChild( APSME_TransportKeyInd_t* ind )
{
  // verify from Trust Center
  if ( ind->srcAddr == APSME_TRUSTCENTER_NWKADDR )
  {
    // check for initial NWK key
    if ( ( ind->keyType == KEY_TYPE_NWK      ) ||
         ( ind->keyType == 6                 ) ||
         ( ind->keyType == KEY_TYPE_NWK_HIGH )    )
    {
      // set association status to authenticated
      ZDSecMgrAssocDeviceAuth( AssocGetWithExt( ind->dstExtAddr ) );
    }

    return TRUE;
  }

  return FALSE;
}


ZStatus_t ZDSecMgrAddLinkKey( uint16 shortAddr, uint8 *extAddr, uint8 *key)
{
  uint16           ami;
  ZDSecMgrEntry_t* entry;

  /* Store the device address in the addr manager */
  if( ZDSecMgrAddrStore( shortAddr, extAddr, &ami ) != ZSuccess )
  {
    /* Adding to Addr Manager fails */
    return ZFailure;
  }

  /* Lookup entry using specified address index */
  ZDSecMgrEntryLookupAMI( ami, &entry );

  // If no existing entry, create one
  if ( entry == NULL )
  {
    if ( ZDSecMgrEntryNew( &entry ) == ZSuccess )
    {
      entry->ami = ami;
    }
    else
    {
      /* Security Manager full */
      return ZBufferFull;
    }
  }
  // Write the link key
  APSME_LinkKeySet( extAddr, key );

#if defined (TC_LINKKEY_JOIN)
  // Mark the device as authenticated.
  ZDSecMgrAuthenticationSet( extAddr, ZDSecMgr_Authenticated_CBCK );
#endif

#if defined NV_RESTORE
  ZDSecMgrWriteNV();  // Write the new established link key to NV.
#endif

  return ZSuccess;
}

#if defined ( NV_RESTORE )

uint8 ZDSecMgrInitNV(void)
{

  uint8 rtrn = osal_nv_item_init(ZCD_NV_APS_LINK_KEY_TABLE,
                (sizeof(nvDeviceListHdr_t) + (sizeof(ZDSecMgrEntry_t) * ZDSECMGR_ENTRY_MAX)), NULL);

  // If the item does not already exist, set all values to 0
  if (rtrn != SUCCESS)
  {
    nvDeviceListHdr_t hdr;
    hdr.numRecs = 0;
    osal_nv_write(ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof(nvDeviceListHdr_t), &hdr);
  }

  return rtrn;
}
#endif // NV_RESTORE

#if defined ( NV_RESTORE )

static void ZDSecMgrWriteNV( void )
{
  uint16 i;
  nvDeviceListHdr_t hdr;

  hdr.numRecs = 0;

  if (ZDSecMgrEntries != NULL)
  {
    for ( i = 0; i < ZDSECMGR_ENTRY_MAX; i++ )
    {
      // Save off the record
      osal_nv_write( ZCD_NV_APS_LINK_KEY_TABLE,
                    (uint16)((sizeof(nvDeviceListHdr_t)) + (i * sizeof(ZDSecMgrEntry_t))),
                    sizeof(ZDSecMgrEntry_t), &ZDSecMgrEntries[i] );

      if ( ZDSecMgrEntries[i].ami != INVALID_NODE_ADDR )
      {
        hdr.numRecs++;
      }
    }
  }

  // Save off the header
  osal_nv_write( ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof( nvDeviceListHdr_t ), &hdr );
}
#endif // NV_RESTORE

#if defined ( NV_RESTORE )

static void ZDSecMgrRestoreFromNV( void )
{
  nvDeviceListHdr_t hdr;
  APSME_LinkKeyData_t *pApsLinkKey = NULL;

  if ((osal_nv_read(ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof(nvDeviceListHdr_t), &hdr) == ZSUCCESS) &&
      ((hdr.numRecs > 0) && (hdr.numRecs <= ZDSECMGR_ENTRY_MAX)))
  {
    uint8 x;

    pApsLinkKey = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

    for (x = 0; x < ZDSECMGR_ENTRY_MAX; x++)
    {
      if ( osal_nv_read( ZCD_NV_APS_LINK_KEY_TABLE,
                        (uint16)(sizeof(nvDeviceListHdr_t) + (x * sizeof(ZDSecMgrEntry_t))),
                        sizeof(ZDSecMgrEntry_t), &ZDSecMgrEntries[x] ) == SUCCESS )
      {
        // update data only for valid entries
        if ( ZDSecMgrEntries[x].ami != INVALID_NODE_ADDR )
        {
          if (pApsLinkKey != NULL)
          {
            // read the key form NV, keyNvId must be ZCD_NV_APS_LINK_KEY_DATA_START based
            osal_nv_read( ZDSecMgrEntries[x].keyNvId, 0,
                         sizeof(APSME_LinkKeyData_t), pApsLinkKey );

            // set new values for the counter
            pApsLinkKey->txFrmCntr += ( MAX_APS_FRAMECOUNTER_CHANGES + 1 );

            // restore values for counters in RAM
            ApsLinkKeyFrmCntr[ZDSecMgrEntries[x].keyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].txFrmCntr =
                                            pApsLinkKey->txFrmCntr;

            ApsLinkKeyFrmCntr[ZDSecMgrEntries[x].keyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].rxFrmCntr =
                                            pApsLinkKey->rxFrmCntr;

            osal_nv_write( ZDSecMgrEntries[x].keyNvId, 0,
                          sizeof(APSME_LinkKeyData_t), pApsLinkKey );

            // clear copy of key in RAM
            osal_memset(pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t));
          }
        }
      }
    }

    if (pApsLinkKey != NULL)
    {
      osal_mem_free(pApsLinkKey);
    }
  }
}
#endif // NV_RESTORE

void ZDSecMgrSetDefaultNV( void )
{
  uint16 i;
  nvDeviceListHdr_t hdr;
  ZDSecMgrEntry_t secMgrEntry;
  APSME_LinkKeyData_t *pApsLinkKey = NULL;

  // Initialize the header
  hdr.numRecs = 0;

  // clear the header
  osal_nv_write(ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof(nvDeviceListHdr_t), &hdr);

  osal_memset( &secMgrEntry, 0x00, sizeof(ZDSecMgrEntry_t) );

  for ( i = 0; i < ZDSECMGR_ENTRY_MAX; i++ )
  {
    // Clear the record
    osal_nv_write( ZCD_NV_APS_LINK_KEY_TABLE,
                (uint16)((sizeof(nvDeviceListHdr_t)) + (i * sizeof(ZDSecMgrEntry_t))),
                        sizeof(ZDSecMgrEntry_t), &secMgrEntry );
  }

  pApsLinkKey = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

  if (pApsLinkKey != NULL)
  {
    osal_memset( pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t) );

    for ( i = 0; i < ZDSECMGR_ENTRY_MAX; i++ )
    {
      // Clear the record
      osal_nv_write( (ZCD_NV_APS_LINK_KEY_DATA_START + i), 0,
                    sizeof(APSME_LinkKeyData_t), pApsLinkKey);
    }

    osal_mem_free(pApsLinkKey);
  }
}

#if defined ( NV_RESTORE )

static void ZDSecMgrUpdateNV( uint16 index )
{
  nvDeviceListHdr_t hdr;

  if (ZDSecMgrEntries != NULL)
  {
    // Save off the record
    osal_nv_write( ZCD_NV_APS_LINK_KEY_TABLE,
                   (uint16)((sizeof(nvDeviceListHdr_t)) + (index * sizeof(ZDSecMgrEntry_t))),
                   sizeof(ZDSecMgrEntry_t), &ZDSecMgrEntries[index] );
  }

  if (osal_nv_read(ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof(nvDeviceListHdr_t), &hdr) == ZSUCCESS)
  {
    if ( ZDSecMgrEntries[index].ami == INVALID_NODE_ADDR )
    {
      if (hdr.numRecs > 0)
      {
        hdr.numRecs--;
      }
    }
    else
    {
      hdr.numRecs++;
    }

    // Save off the header
    osal_nv_write( ZCD_NV_APS_LINK_KEY_TABLE, 0, sizeof( nvDeviceListHdr_t ), &hdr );
  }
}
#endif // NV_RESTORE

ZStatus_t ZDSecMgrAPSRemove( uint16 nwkAddr, uint8 *extAddr, uint16 parentAddr )
{
  ZDSecMgrDevice_t device;

  if ( ( nwkAddr == INVALID_NODE_ADDR ) ||
       ( extAddr == NULL )              ||
       ( parentAddr == INVALID_NODE_ADDR ) )
  {
    return ( ZFailure );
  }

  device.nwkAddr = nwkAddr;
  device.extAddr = extAddr;
  device.parentAddr = parentAddr;

  // remove device
  ZDSecMgrDeviceRemove( &device );

  return ( ZSuccess );
}

void APSME_TCLinkKeyInit(uint8 setDefault)
{
  uint8             i;
  APSME_TCLinkKey_t tcLinkKey;
  uint8             rtrn;

  // Initialize all NV items for preconfigured TCLK
  for( i = 0; i < ZDSECMGR_TC_DEVICE_MAX; i++ )
  {
    // Making sure data is cleared for every key all the time
    osal_memset( &tcLinkKey, 0x00, sizeof(APSME_TCLinkKey_t) );

    // Initialize first element of the table with the default TCLK
    if((i == 0) && ( zgUseDefaultTCLK == TRUE ))
    {
      osal_memset( tcLinkKey.extAddr, 0xFF, Z_EXTADDR_LEN );
      osal_memcpy( tcLinkKey.key, defaultTCLinkKey, SEC_KEY_LEN);
    }

    // If the item doesn't exist in NV memory, create and initialize
    // it with the default value passed in, either defaultTCLK or 0
    rtrn = osal_nv_item_init( (ZCD_NV_TCLK_TABLE_START + i),
                               sizeof(APSME_TCLinkKey_t), &tcLinkKey);

    if (rtrn == SUCCESS)
    {
      // set the Frame counters to 0 to existing keys in NV
      osal_nv_read( ( ZCD_NV_TCLK_TABLE_START + i), 0,
                     sizeof(APSME_TCLinkKey_t), &tcLinkKey );

#if defined ( NV_RESTORE )
      if (setDefault == TRUE)
      {
        // clear the value stored in NV
        tcLinkKey.txFrmCntr = 0;
      }
      else
      {
        // increase the value stored in NV
        tcLinkKey.txFrmCntr += ( MAX_TCLK_FRAMECOUNTER_CHANGES + 1 );
      }
#else
      // Clear the counters if NV_RESTORE is not enabled and this NV item
      // already existed in the NV memory
      tcLinkKey.txFrmCntr = 0;
      tcLinkKey.rxFrmCntr = 0;
#endif  // NV_RESTORE

      osal_nv_write( ( ZCD_NV_TCLK_TABLE_START + i), 0,
                      sizeof(APSME_TCLinkKey_t), &tcLinkKey );

      // set initial values for counters in RAM
      TCLinkKeyFrmCntr[i].txFrmCntr = tcLinkKey.txFrmCntr;
      TCLinkKeyFrmCntr[i].rxFrmCntr = tcLinkKey.rxFrmCntr;
    }
  }

  // clear copy of key in RAM
  osal_memset( &tcLinkKey, 0x00, sizeof(APSME_TCLinkKey_t) );

}

ZStatus_t APSME_TCLinkKeySync( uint16 srcAddr, SSP_Info_t* si )
{
  uint8 i;
  ZStatus_t status = ZSecNoKey;
  APSME_TCLinkKey_t tcLinkKey;
  uint32 *tclkRxFrmCntr;

  // Look up the IEEE address of the trust center if it's available
  if ( AddrMgrExtAddrValid( si->extAddr ) == FALSE )
  {
    APSME_LookupExtAddr( srcAddr, si->extAddr );
  }

  // Look up the TC link key associated with the device
  // or the default TC link key (extAddr is all FFs), whichever is found
  for( i = 0; i < ZDSECMGR_TC_DEVICE_MAX; i++ )
  {
    // Read entry i of the TC link key table from NV
    osal_nv_read( (ZCD_NV_TCLK_TABLE_START + i), 0,
                 sizeof(APSME_TCLinkKey_t), &tcLinkKey );

    if( AddrMgrExtAddrEqual(si->extAddr, tcLinkKey.extAddr) ||
        APSME_IsDefaultTCLK(tcLinkKey.extAddr))
    {
      tclkRxFrmCntr = &TCLinkKeyFrmCntr[i].rxFrmCntr;

      // verify that the incoming frame counter is valid
      if ( si->frmCntr >= *tclkRxFrmCntr )
      {
        // set the keyNvId to use
        si->keyNvId = (ZCD_NV_TCLK_TABLE_START + i);

        // update the rx frame counter
        *tclkRxFrmCntr = si->frmCntr + 1;

        status = ZSuccess;
      }
      else
      {
        status = ZSecOldFrmCount;
      }
      // break from the loop
      break;
    }
  }

  // clear copy of key in RAM
  osal_memset( &tcLinkKey, 0x00, sizeof(APSME_TCLinkKey_t) );

  return status;
}

ZStatus_t APSME_TCLinkKeyLoad( uint16 dstAddr, SSP_Info_t* si )
{
  uint8 i;
  ZStatus_t status = ZSecNoKey;
  APSME_TCLinkKey_t tcLinkKey;
  AddrMgrEntry_t addrEntry;
  uint32 *tclkTxFrmCntr;
  uint8 extAddrFound;
  uint8 defaultTCLKIdx = ZDSECMGR_TC_DEVICE_MAX;

  // Look up the ami of the srcAddr if available
  addrEntry.user    = ADDRMGR_USER_DEFAULT;
  addrEntry.nwkAddr = dstAddr;

  APSME_LookupExtAddr( dstAddr, si->extAddr );

  extAddrFound = AddrMgrExtAddrValid( si->extAddr );

  // Look up the TC link key associated with the device
  // or the master TC link key (ami = 0xFFFF), whichever is found
  for( i = 0; i < ZDSECMGR_TC_DEVICE_MAX; i++ )
  {
    // Read entry i of the TC link key table from NV
    osal_nv_read( (ZCD_NV_TCLK_TABLE_START + i), 0,
                 sizeof(APSME_TCLinkKey_t), &tcLinkKey );

    if( extAddrFound && AddrMgrExtAddrEqual(si->extAddr, tcLinkKey.extAddr) )
    {
      status = ZSuccess;

      break; // break from the loop
    }

    if ( APSME_IsDefaultTCLK(tcLinkKey.extAddr) )
    {
      if ( !extAddrFound )
      {
        status = ZSuccess;

        break; // break from the loop
      }

      // Remember the default TCLK index
      defaultTCLKIdx = i;
    }
  }

  if ( (status != ZSuccess) && (defaultTCLKIdx < ZDSECMGR_TC_DEVICE_MAX) )
  {
    // Exact match was not found; use the default TC Link Key
    i = defaultTCLKIdx;
    status = ZSuccess;
  }

  if ( status == ZSuccess )
  {
    tclkTxFrmCntr = &TCLinkKeyFrmCntr[i].txFrmCntr;

    // set the keyNvId to use
    si->keyNvId = (ZCD_NV_TCLK_TABLE_START + i);

    // update link key related fields
    si->keyID   = SEC_KEYID_LINK;
    si->frmCntr = *tclkTxFrmCntr;

    // update outgoing frame counter
    (*tclkTxFrmCntr)++;

#if defined ( NV_RESTORE )
    // write periodically to NV
    if ( !(*tclkTxFrmCntr % MAX_TCLK_FRAMECOUNTER_CHANGES) )
    {
      // set the flag to write key to NV
      TCLinkKeyFrmCntr[i].pendingFlag = TRUE;

      // Notify the ZDApp that the frame counter has changed.
      osal_set_event( ZDAppTaskID, ZDO_TCLK_FRAMECOUNTER_CHANGE );
    }
#endif
  }

  // If no TC link key found, remove the device from the address manager
  if ( (status != ZSuccess) && (AddrMgrEntryLookupNwk(&addrEntry) == TRUE) )
  {
    AddrMgrEntryRelease( &addrEntry );
  }

    // clear copy of key in RAM
  osal_memset( &tcLinkKey, 0x00, sizeof(APSME_TCLinkKey_t) );

  return status;
}

uint8 APSME_IsDefaultTCLK( uint8 *extAddr )
{
  uint8 i = 0;

  if( extAddr == NULL )
  {
    return FALSE;
  }

  while( i++ < Z_EXTADDR_LEN )
  {
    if( *extAddr++ != 0xFF )
    {
      return FALSE;
    }
  }

  return TRUE;
}

void ZDSecMgrNwkKeyInit(uint8 setDefault)
{
  uint8 status;
  nwkKeyDesc nwkKey;

  // Initialize NV items for NWK key, this structure contains the frame counter
  // and is only used when NV_RESTORE is enabled
  nwkActiveKeyItems keyItems;

  osal_memset( &keyItems, 0, sizeof( nwkActiveKeyItems ) );

  status = osal_nv_item_init( ZCD_NV_NWKKEY, sizeof(nwkActiveKeyItems), (void *)&keyItems );

#if defined ( NV_RESTORE )
  // reset the values of NV items if NV_RESTORE is not enabled
  if ((status == SUCCESS) && (setDefault == TRUE))
  {
    // clear NV data to default values
    osal_nv_write( ZCD_NV_NWKKEY, 0, sizeof(nwkActiveKeyItems), &keyItems );
  }
#else
  (void)setDefault;   // to eliminate compiler warning

  // reset the values of NV items if NV_RESTORE is not enabled
  if (status == SUCCESS)
  {
    osal_nv_write( ZCD_NV_NWKKEY, 0, sizeof(nwkActiveKeyItems), &keyItems );
  }
#endif // defined (NV_RESTORE)

  // Initialize NV items for NWK Active and Alternate keys. These items are used
  // all the time, independently of NV_RESTORE being set or not
  osal_memset( &nwkKey, 0x00, sizeof(nwkKey) );

  status = osal_nv_item_init( ZCD_NV_NWK_ACTIVE_KEY_INFO, sizeof(nwkKey), &nwkKey);

#if defined ( NV_RESTORE )
  // reset the values of NV items if NV_RESTORE is not enabled
  if ((status == SUCCESS) && (setDefault == TRUE))
  {
    // clear NV data to default values
    osal_nv_write( ZCD_NV_NWK_ACTIVE_KEY_INFO, 0, sizeof(nwkKey), &nwkKey );
  }
#else
  // reset the values of NV items if NV_RESTORE is not enabled
  if (status == SUCCESS)
  {
    osal_nv_write( ZCD_NV_NWK_ACTIVE_KEY_INFO, 0, sizeof(nwkKey), &nwkKey );
  }
#endif // defined (NV_RESTORE)

  status = osal_nv_item_init( ZCD_NV_NWK_ALTERN_KEY_INFO, sizeof(nwkKey), &nwkKey );

#if defined ( NV_RESTORE )
  // reset the values of NV items if NV_RESTORE is not enabled
  if ((status == SUCCESS) && (setDefault == TRUE))
  {
    // clear NV data to default values
    osal_nv_write( ZCD_NV_NWK_ALTERN_KEY_INFO, 0, sizeof(nwkKey), &nwkKey );
  }
#else
  // reset the values of NV items if NV_RESTORE is not enabled
  if (status == SUCCESS)
  {
    osal_nv_write( ZCD_NV_NWK_ALTERN_KEY_INFO, 0, sizeof(nwkKey), &nwkKey );
  }
#endif // defined (NV_RESTORE)

}

ZStatus_t ZDSecMgrReadKeyFromNv(uint16 keyNvId, void *keyinfo)
{
  if ((keyNvId == ZCD_NV_NWK_ACTIVE_KEY_INFO) ||
      (keyNvId == ZCD_NV_NWK_ALTERN_KEY_INFO))
  {
    // get NWK active or alternate key from NV
    return (osal_nv_read(keyNvId,
                         osal_offsetof(nwkKeyDesc, key),
                         SEC_KEY_LEN,
                         keyinfo));
  }
  else if ((keyNvId >= ZCD_NV_TCLK_TABLE_START) &&
           (keyNvId < (ZCD_NV_TCLK_TABLE_START + ZDSECMGR_TC_DEVICE_MAX)))
  {
    // Read entry keyNvId of the TC link key table from NV. keyNvId should be
    // ZCD_NV_TCLK_TABLE_START + <offset_in_table>
    return (osal_nv_read(keyNvId,
                         osal_offsetof(APSME_TCLinkKey_t, key),
                         SEC_KEY_LEN,
                         keyinfo));
  }
  else if ((keyNvId >= ZCD_NV_APS_LINK_KEY_DATA_START) &&
           (keyNvId < (ZCD_NV_APS_LINK_KEY_DATA_START + ZDSECMGR_ENTRY_MAX)))
  {
    // Read entry keyNvId of the APS link key table from NV. keyNvId should be
    // ZCD_NV_APS_LINK_KEY_DATA_START + <offset_in_table>
    return (osal_nv_read(keyNvId,
                         osal_offsetof(APSME_LinkKeyData_t, key),
                         SEC_KEY_LEN,
                         keyinfo));
  }
  else if ((keyNvId >= ZCD_NV_MASTER_KEY_DATA_START) &&
           (keyNvId < (ZCD_NV_MASTER_KEY_DATA_START + ZDSECMGR_MASTERKEY_MAX)))
  {
    // Read entry keyNvId of the MASTER key table from NV. keyNvId should be
    // ZCD_NV_MASTER_KEY_DATA_START + <offset_in_table>
    return (osal_nv_read(keyNvId,
                         osal_offsetof(ZDSecMgrMasterKeyData_t, key),
                         SEC_KEY_LEN,
                         keyinfo));
  }
  else if (keyNvId == ZCD_NV_PRECFGKEY)
  {
    // Read entry keyNvId of the Preconfig key from NV.
    return (osal_nv_read(keyNvId,
                         0,
                         SEC_KEY_LEN,
                         keyinfo));
  }

  return NV_OPER_FAILED;
}

void ZDSecMgrApsLinkKeyInit(void)
{
  APSME_LinkKeyData_t pApsLinkKey;
  uint8 i;
  uint8 status;

  // Initialize all NV items for APS link key, if not exist already.
  osal_memset( &pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t) );

  for( i = 0; i < ZDSECMGR_ENTRY_MAX; i++ )
  {
    status = osal_nv_item_init( (ZCD_NV_APS_LINK_KEY_DATA_START + i),
                               sizeof(APSME_LinkKeyData_t), &pApsLinkKey );

#if defined ( NV_RESTORE )
    (void)status;   // to eliminate compiler warning
#else
    // reset the values of NV items if NV_RESTORE is not enabled
    if (status == SUCCESS)
    {
      osal_nv_write( (ZCD_NV_APS_LINK_KEY_DATA_START + i), 0,
                    sizeof(APSME_LinkKeyData_t), &pApsLinkKey );

    }
#endif // defined (NV_RESTORE)
  }
}

void ZDSecMgrInitNVKeyTables(uint8 setDefault)
{
  ZDSecMgrNwkKeyInit(setDefault);
  ZDSecMgrMasterKeyInit();
  ZDSecMgrApsLinkKeyInit();
  APSME_TCLinkKeyInit(setDefault);
}

void ZDSecMgrSaveApsLinkKey(void)
{
  APSME_LinkKeyData_t *pKeyData = NULL;
  int i;

  pKeyData = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

  if (pKeyData != NULL)
  {
    // checks all pending flags to know which one to save
    for (i = 0; i < ZDSECMGR_ENTRY_MAX; i++)
    {
      if (ApsLinkKeyFrmCntr[i].pendingFlag == TRUE)
      {
        // retrieve key from NV
        if (osal_nv_read(ZCD_NV_APS_LINK_KEY_DATA_START + i, 0,
                         sizeof(APSME_LinkKeyData_t), pKeyData) == SUCCESS)
        {
          pKeyData->txFrmCntr = ApsLinkKeyFrmCntr[i].txFrmCntr;
          pKeyData->rxFrmCntr = ApsLinkKeyFrmCntr[i].rxFrmCntr;

          // Write the APS link key back to the NV
          osal_nv_write(ZCD_NV_APS_LINK_KEY_DATA_START + i, 0,
                        sizeof(APSME_LinkKeyData_t), pKeyData);

          // clear the pending write flag
          ApsLinkKeyFrmCntr[i].pendingFlag = FALSE;
        }
      }
    }

    // clear copy of key in RAM
    osal_memset( pKeyData, 0x00, sizeof(APSME_LinkKeyData_t) );

    osal_mem_free(pKeyData);
  }
}

void ZDSecMgrSaveTCLinkKey(void)
{
  APSME_TCLinkKey_t *pKeyData = NULL;
  uint16 i;

  pKeyData = (APSME_TCLinkKey_t *)osal_mem_alloc(sizeof(APSME_TCLinkKey_t));

  if (pKeyData != NULL)
  {
    for( i = 0; i < ZDSECMGR_TC_DEVICE_MAX; i++ )
    {
      if (TCLinkKeyFrmCntr[i].pendingFlag == TRUE)
      {
        if (osal_nv_read(ZCD_NV_TCLK_TABLE_START + i, 0,
                         sizeof(APSME_TCLinkKey_t), pKeyData) == SUCCESS)
        {
          pKeyData->txFrmCntr = TCLinkKeyFrmCntr[i].txFrmCntr;
          pKeyData->rxFrmCntr = TCLinkKeyFrmCntr[i].rxFrmCntr;

          // Write the TC link key back to the NV
          osal_nv_write(ZCD_NV_TCLK_TABLE_START + i, 0,
                        sizeof(APSME_TCLinkKey_t), pKeyData);

          // clear the pending write flag
          TCLinkKeyFrmCntr[i].pendingFlag = FALSE;
        }
      }
    }
      // clear copy of key in RAM
    osal_memset( pKeyData, 0x00, sizeof(APSME_TCLinkKey_t) );

    osal_mem_free(pKeyData);
  }
}

#if defined ( ZBA_FALLBACK_NWKKEY )

void ZDSecMgrFallbackNwkKey( void )
{
  if ( !_NIB.nwkKeyLoaded )
  {
    uint8 fallbackKey[SEC_KEY_LEN];

    ZDSecMgrReadKeyFromNv( ZCD_NV_PRECFGKEY, fallbackKey );
    SSP_UpdateNwkKey( fallbackKey, 0);
    SSP_SwitchNwkKey( 0 );

    // clear local copy of key
    osal_memset( fallbackKey, 0x00, SEC_KEY_LEN );

    // handle next step in authentication process
    ZDSecMgrAuthNwkKey();
  }
}
#endif // defined ( ZBA_FALLBACK_NWKKEY )

#if defined ( NV_RESTORE )

void ZDSecMgrClearNVKeyValues(void)
{
  nwkActiveKeyItems keyItems;
  nwkKeyDesc nwkKey;

  osal_memset(&keyItems, 0x00, sizeof(nwkActiveKeyItems));

  osal_nv_write(ZCD_NV_NWKKEY, 0, sizeof(nwkActiveKeyItems), &keyItems);

  // Initialize NV items for NWK Active and Alternate keys.
  osal_memset( &nwkKey, 0x00, sizeof(nwkKeyDesc) );

  osal_nv_write(ZCD_NV_NWK_ACTIVE_KEY_INFO, 0, sizeof(nwkKeyDesc), &nwkKey);

  osal_nv_write(ZCD_NV_NWK_ALTERN_KEY_INFO, 0, sizeof(nwkKeyDesc), &nwkKey);
}
#endif

ZDSecMgr.h

#ifndef ZDSECMGR_H
#define ZDSECMGR_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ZComDef.h"
#include "ZDApp.h"

typedef enum
{
  ZDSecMgr_Not_Authenticated = 0,   // The device has not been authenticated
  ZDSecMgr_Authenticated_CBCK,      // The devcie has been authenticated using CBKE
  ZDSecMgr_Authenticated_EA         // The device has been authenticated using EA
}ZDSecMgr_Authentication_Option;

extern void ZDSecMgrInit(uint8 state);

extern void ZDSecMgrConfig( void );

extern uint8 ZDSecMgrPermitJoining( uint8 duration );

extern void ZDSecMgrPermitJoiningTimeout( void );

extern uint8 ZDSecMgrNewDeviceEvent( void );

extern void ZDSecMgrEvent( void );

extern void ZDSecMgrEstablishKeyCfm( ZDO_EstablishKeyCfm_t* cfm );

extern void ZDSecMgrEstablishKeyInd( ZDO_EstablishKeyInd_t* ind );

extern void ZDSecMgrTransportKeyInd( ZDO_TransportKeyInd_t* ind );

extern void ZDSecMgrUpdateDeviceInd( ZDO_UpdateDeviceInd_t* ind );

extern void ZDSecMgrRemoveDeviceInd( ZDO_RemoveDeviceInd_t* ind );

extern void ZDSecMgrRequestKeyInd( ZDO_RequestKeyInd_t* ind );

extern void ZDSecMgrSwitchKeyInd( ZDO_SwitchKeyInd_t* ind );

extern void ZDSecMgrAuthenticateInd( ZDO_AuthenticateInd_t* ind );

extern void ZDSecMgrAuthenticateCfm( ZDO_AuthenticateCfm_t* cfm );

extern ZStatus_t ZDSecMgrUpdateNwkKey( uint8* key, uint8 keySeqNum, uint16 dstAddr );

extern ZStatus_t ZDSecMgrSwitchNwkKey( uint8 keySeqNum, uint16 dstAddr );

extern ZStatus_t ZDSecMgrRequestAppKey( uint8 *partExtAddr );

ZStatus_t ZDSecMgrSetupPartner( uint16 partNwkAddr, uint8* partExtAddr );

ZStatus_t ZDSecMgrAppKeyTypeSet( uint8 keyType );

extern ZStatus_t ZDSecMgrAddLinkKey( uint16 shortAddr, uint8 *extAddr, uint8 *key);

extern ZStatus_t ZDSecMgrDeviceRemoveByExtAddr( uint8 *pAddr );

extern ZStatus_t ZDSecMgrAddrClear( uint8* extAddr );

extern uint8 ZDSecMgrInitNV( void );

extern void ZDSecMgrSetDefaultNV( void );

ZStatus_t ZDSecMgrAPSRemove( uint16 nwkAddr, uint8 *extAddr, uint16 parentAddr );

uint8 ZDSecMgrAuthenticationCheck( uint16 shortAddr );

extern ZStatus_t APSME_TCLinkKeySync( uint16 srcAddr, SSP_Info_t* si );

extern ZStatus_t APSME_TCLinkKeyLoad( uint16 dstAddr, SSP_Info_t* si );

extern ZStatus_t ZDSecMgrReadKeyFromNv(uint16 keyNvId, void *keyinfo);

extern void ZDSecMgrInitNVKeyTables(uint8 setDefault);

extern void ZDSecMgrSaveApsLinkKey(void);

extern void ZDSecMgrSaveTCLinkKey(void);

extern void ZDSecMgrClearNVKeyValues(void);

extern void ZDSecMgrFallbackNwkKey( void );

#ifdef __cplusplus
}
#endif

#endif /* ZDSECMGR_H */

ZMac(ZMAC层)

zmac.c

#include "ZComDef.h"
#include "OSAL.h"
#include "ZMAC.h"
#include "mac_main.h"
#include "ssp.h"

#if !defined NONWK
  #include "ZGlobals.h"
#endif

uint32 _ScanChannels;

extern uint8 aExtendedAddress[];


extern void MAC_SetRandomSeedCB(macRNGFcn_t pCBFcn);

/* Pointer to scan result buffer */
void *ZMac_ScanBuf = NULL;

uint8 ZMacInit( void )
{
  uint8 stat;

#if defined( ZCL_KEY_ESTABLISH )
  /* Set the callback function for 16 byte random seed */
  MAC_SetRandomSeedCB( SSP_StoreRandomSeedNV);
#endif

  MAC_Init();
  MAC_InitDevice();

#if !defined NONWK
  if ( ZG_BUILD_RTR_TYPE )
  {
    MAC_InitCoord();
  }
#endif

  // If OK, initialize the MAC
  stat = ZMacReset( TRUE );

  // Turn off interrupts
  osal_int_disable( INTS_ALL );

  return ( stat );
}

uint8 ZMacReset( bool SetDefaultPIB )
{
  byte stat;
  byte value;

  stat = MAC_MlmeResetReq( SetDefaultPIB );

  // Don't send PAN ID conflict
  value = FALSE;
  MAC_MlmeSetReq( MAC_ASSOCIATED_PAN_COORD, &value );
  MAC_MlmeSetReq( MAC_EXTENDED_ADDRESS, &aExtendedAddress );

  if (ZMac_ScanBuf)
  {
    osal_mem_free(ZMac_ScanBuf);
    ZMac_ScanBuf = NULL;
  }

  return ( stat );
}


uint8 ZMacGetReq( uint8 attr, uint8 *value )
{
  if ( attr == ZMacExtAddr )
  {
    osal_cpyExtAddr( value, &aExtendedAddress );
    return ZMacSuccess;
  }

  return (ZMacStatus_t) MAC_MlmeGetReq( attr, value );
}


uint8 ZMacSetReq( uint8 attr, byte *value )
{
  if ( attr == ZMacExtAddr )
  {
    osal_cpyExtAddr( aExtendedAddress, value );
  }

  return (ZMacStatus_t) MAC_MlmeSetReq( attr, value );
}

#ifdef MAC_SECURITY

uint8 ZMacSecurityGetReq( uint8 attr, uint8 *value )
{
  return (ZMacStatus_t) MAC_MlmeGetSecurityReq( attr, value );
}


uint8 ZMacSecuritySetReq( uint8 attr, byte *value )
{
  return (ZMacStatus_t) MAC_MlmeSetSecurityReq( attr, value );
}
#endif /* MAC_SECURITY */

uint8 ZMacAssociateReq( ZMacAssociateReq_t *pData )
{
  /* Right now, set security to zero */
  pData->Sec.SecurityLevel = false;

  MAC_MlmeAssociateReq ( (macMlmeAssociateReq_t *)pData);
  return ( ZMacSuccess );
}

uint8 ZMacAssociateRsp( ZMacAssociateRsp_t *pData )
{
  /* TBD: set security to zero for now. Require Ztool change */
  pData->Sec.SecurityLevel = false;

  return ( MAC_MlmeAssociateRsp( (macMlmeAssociateRsp_t *) pData ) );
}

uint8 ZMacDisassociateReq( ZMacDisassociateReq_t *pData )
{
  /* Right now, set security to zero */
  pData->Sec.SecurityLevel = false;

  MAC_MlmeDisassociateReq( (macMlmeDisassociateReq_t *)pData);
  return ( ZMacSuccess );
}

uint8 ZMacOrphanRsp( ZMacOrphanRsp_t *pData )
{
  /* Right now, set security to zero */
  pData->Sec.SecurityLevel = false;

  MAC_MlmeOrphanRsp( (macMlmeOrphanRsp_t *)pData);
  return ( ZMacSuccess );
}

uint8 ZMacScanReq( ZMacScanReq_t *pData )
{
  _ScanChannels = pData->ScanChannels;

  /* scan in progress */
  if (ZMac_ScanBuf != NULL)
  {
    return MAC_SCAN_IN_PROGRESS;
  }

  if (pData->ScanType != ZMAC_ORPHAN_SCAN)
  {
    /* Allocate memory depends on the scan type */
    if (pData->ScanType == ZMAC_ED_SCAN)
    {
      if ((ZMac_ScanBuf = osal_mem_alloc(ZMAC_ED_SCAN_MAXCHANNELS)) == NULL)
      {
        return MAC_NO_RESOURCES;
      }
      osal_memset(ZMac_ScanBuf, 0, ZMAC_ED_SCAN_MAXCHANNELS);
      pData->Result.pEnergyDetect = ((uint8*)ZMac_ScanBuf) + MAC_CHAN_11;
    }
    else if (pData->MaxResults > 0)
    {
      if ((ZMac_ScanBuf = pData->Result.pPanDescriptor =
           osal_mem_alloc( sizeof( ZMacPanDesc_t ) * pData->MaxResults )) == NULL)
      {
        return MAC_NO_RESOURCES;
      }
    }
  }

  /* Channel Page */
  pData->ChannelPage = 0x00;

  MAC_MlmeScanReq ((macMlmeScanReq_t *)pData);

  return ZMacSuccess;
}

uint8 ZMacStartReq( ZMacStartReq_t *pData )
{
  uint8 stat;

  // Probably want to keep the receiver on
  stat = true;
  MAC_MlmeSetReq( MAC_RX_ON_WHEN_IDLE, &stat );

  /* Right now, set security to zero */
  pData->RealignSec.SecurityLevel = false;
  pData->BeaconSec.SecurityLevel = false;


  MAC_MlmeStartReq((macMlmeStartReq_t *) pData);

  // MAC does not issue mlmeStartConfirm(), so we have to
  // mlmeStartConfirm( stat );  This needs to be addressed some how

  return ZMacSuccess;
}

uint8 ZMacSyncReq( ZMacSyncReq_t *pData )
{
  MAC_MlmeSyncReq( (macMlmeSyncReq_t *)pData);
  return ZMacSuccess;
}

uint8 ZMacPollReq( ZMacPollReq_t *pData )
{
  /* Right now, set security to zero */
  pData->Sec.SecurityLevel = false;

  MAC_MlmePollReq ((macMlmePollReq_t *)pData);
  return ( ZMacSuccess );
}

uint8 ZMacDataReqSec( ZMacDataReq_t *pData, applySecCB_t secCB )
{
  macMcpsDataReq_t *pBuf;

  /* Allocate memory */
  pBuf = MAC_McpsDataAlloc( pData->msduLength, pData->Sec.SecurityLevel, pData->Sec.KeyIdMode );

  if ( pBuf )
  {
    /* Copy the addresses */
    osal_memcpy( &pBuf->mac, pData, sizeof (macDataReq_t) );

    /* Copy data */
    osal_memcpy( pBuf->msdu.p, pData->msdu, pData->msduLength );

    /* Copy Security parameters */
    osal_memcpy( &pBuf->sec, &pData->Sec, sizeof (macSec_t));

    /* Encrypt in place */
    if ( secCB && pBuf->msdu.len && pBuf->msdu.p )
    {
      if ( secCB( pBuf->msdu.len, pBuf->msdu.p ) != ZSuccess )
      {
        // Deallocate the buffer.  MAC_McpsDataAlloc() calls osal_msg_allocate() and
        // returns the same pointer.
        osal_msg_deallocate( (uint8 *)pBuf );

        return ( MAC_NO_RESOURCES );
      }
    }

    /* Call Mac Data Request */
    MAC_McpsDataReq( pBuf );

    return ( ZMacSuccess );
  }

  return ( MAC_NO_RESOURCES );
}

uint8 ZMacDataReq( ZMacDataReq_t *pData )
{
  return ZMacDataReqSec( pData, NULL );
}

uint8 ZMacPurgeReq( byte Handle )
{
  MAC_McpsPurgeReq( Handle );
  return ZMacSuccess;
}

ZMacStatus_t ZMacSrcMatchEnable (uint8 addrType, uint8 numEntries)
{
  return (MAC_SrcMatchEnable(addrType, numEntries));
}

ZMacStatus_t ZMacSrcMatchAddEntry (zAddrType_t *addr, uint16 panID)
{
  return (MAC_SrcMatchAddEntry ((sAddr_t*)addr, panID));
}

ZMacStatus_t ZMacSrcMatchDeleteEntry (zAddrType_t *addr, uint16 panID)
{
  return (MAC_SrcMatchDeleteEntry ((sAddr_t*)addr, panID));
}

ZMacStatus_t ZMacSrcMatchAckAllPending (uint8 option)
{
  MAC_SrcMatchAckAllPending (option);

  return ZMacSuccess;
}

ZMacStatus_t ZMacSrcMatchCheckAllPending (void)
{
  return (MAC_SrcMatchCheckAllPending ());
}

void ZMacPwrOnReq ( void )
{
  MAC_PwrOnReq();
}


uint8 ZMac_PwrMode(void)
{
  return (MAC_PwrMode());
}

uint8 ZMacSetTransmitPower( ZMacTransmitPower_t level )
{
  return MAC_MlmeSetReq( ZMacPhyTransmitPowerSigned, &level );
}

void ZMacSendNoData ( uint16 DstAddr, uint16 DstPANId )
{
  macMcpsDataReq_t *pBuf;

  /* Allocate memory */
  pBuf = MAC_McpsDataAlloc(0, MAC_SEC_LEVEL_NONE, MAC_KEY_ID_MODE_NONE);

  if (pBuf)
  {
    /* Fill in src information */
    pBuf->mac.srcAddrMode              = SADDR_MODE_SHORT;

    /* Fill in dst information */
    pBuf->mac.dstAddr.addr.shortAddr   = DstAddr;
    pBuf->mac.dstAddr.addrMode         = SADDR_MODE_SHORT;
    pBuf->mac.dstPanId                 = DstPANId;

    /* Misc information */
    pBuf->mac.msduHandle               = 0;
    pBuf->mac.txOptions                = ZMAC_TXOPTION_ACK | ZMAC_TXOPTION_NO_RETRANS | ZMAC_TXOPTION_NO_CNF;

    /* Right now, set security to zero */
    pBuf->sec.securityLevel = false;

    /* Call Mac Data Request */
    MAC_McpsDataReq(pBuf);
  }

}

uint8 ZMacStateIdle( void )
{
  return macStateIdle();
}

ZMAC.h

#ifndef ZMAC_H
#define ZMAC_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ZComDef.h"
#include "zmac_internal.h"


/* Maximum length of the beacon payload */
#ifndef ZMAC_MAX_BEACON_PAYLOAD_LEN
  #define ZMAC_MAX_BEACON_PAYLOAD_LEN    (7 + Z_EXTADDR_LEN)
#endif

#if defined( MAC_API_H )
 #define ZMAC_CHAN_MASK ( \
   MAC_CHAN_11_MASK | \
   MAC_CHAN_12_MASK | \
   MAC_CHAN_13_MASK | \
   MAC_CHAN_14_MASK | \
   MAC_CHAN_15_MASK | \
   MAC_CHAN_16_MASK | \
   MAC_CHAN_17_MASK | \
   MAC_CHAN_18_MASK | \
   MAC_CHAN_19_MASK | \
   MAC_CHAN_20_MASK | \
   MAC_CHAN_21_MASK | \
   MAC_CHAN_22_MASK | \
   MAC_CHAN_23_MASK | \
   MAC_CHAN_24_MASK | \
   MAC_CHAN_25_MASK | \
   MAC_CHAN_26_MASK | \
   MAC_CHAN_27_MASK | \
   MAC_CHAN_28_MASK )
#else
 #define ZMAC_CHAN_MASK  0x07FFF800
#endif

/* LQI adjustment parameters */
#if !defined( LQI_CORR_MIN )
 #define LQI_CORR_MIN  50  /* Theoretical CORR lower limt */
#endif
#if !defined( LQI_CORR_MAX )
 #define LQI_CORR_MAX  110  /* Theoretical CORR upper limt */
#endif


/* ZMAC event header type */
typedef struct
{
  uint8   Event;              /* ZMAC event */
  uint8   Status;             /* ZMAC status */
} ZMacEventHdr_t;

/* Common security type */
typedef struct
{
  uint8 KeySource[ZMAC_KEY_SOURCE_MAX_LEN];
  uint8 SecurityLevel;
  uint8 KeyIdMode;
  uint8 KeyIndex;
}ZMacSec_t;

/* PAN descriptor type */
typedef struct
{
  zAddrType_t   CoordAddress;
  uint16        CoordPANId;
  uint16        SuperframeSpec;
  uint8         LogicalChannel;
  uint8         ChannelPage;
  uint8         GTSPermit;
  uint8         LinkQuality;
  uint32        TimeStamp;
  uint8         SecurityFailure;
  ZMacSec_t     Sec;
} ZMacPanDesc_t;

/* Communication status indication type */
typedef struct
{
  ZMacEventHdr_t hdr;
  zAddrType_t    SrcAddress;
  zAddrType_t    DstAddress;
  uint16         PANId;
  uint8          Reason;
  ZMacSec_t      Sec;
} ZMacCommStatusInd_t;

/* SYNC */

typedef struct
{
  uint8 LogicalChannel;     /* The logical channel to use */
  uint8 ChannelPage;        /* The channel page to use */
  uint8 TrackBeacon;        /* Set to TRUE to continue tracking beacons after synchronizing with the
                               first beacon.  Set to FALSE to only synchronize with the first beacon */
}ZMacSyncReq_t;

/* DATA TYPES */

/* Data request parameters type */
typedef struct
{
  zAddrType_t   DstAddr;
  uint16        DstPANId;
  uint8         SrcAddrMode;
  uint8         Handle;
  uint8         TxOptions;
  uint8         Channel;
  uint8         Power;
  ZMacSec_t     Sec;
  uint8         msduLength;
  uint8        *msdu;
} ZMacDataReq_t;

/* Data confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint8          msduHandle;
  ZMacDataReq_t  *pDataReq;
  uint32         Timestamp;
  uint16         Timestamp2;
  uint8          retries;
  uint8          mpduLinkQuality;
  uint8          correlation;
  int8           rssi;
} ZMacDataCnf_t;


/* ASSOCIATION TYPES */

/* Associate request type */
typedef struct
{
  uint8         LogicalChannel;
  uint8         ChannelPage;
  zAddrType_t   CoordAddress;
  uint16        CoordPANId;
  uint8         CapabilityFlags;
  ZMacSec_t     Sec;
} ZMacAssociateReq_t;

/* Associate response type */
typedef struct
{
  ZLongAddr_t		 DeviceAddress;
  uint16			   AssocShortAddress;
  uint8          Status;
  ZMacSec_t      Sec;
} ZMacAssociateRsp_t;

/* Associate indication parameters type */
typedef struct
{
  ZMacEventHdr_t hdr;
  ZLongAddr_t    DeviceAddress;
  uint8          CapabilityFlags;
  ZMacSec_t      Sec;
} ZMacAssociateInd_t;

/* Associate confim type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint16         AssocShortAddress;
  ZMacSec_t      Sec;
} ZMacAssociateCnf_t;

/* Disassociate request type */
typedef struct
{
  zAddrType_t		DeviceAddress;
  uint16        DevicePanId;
  uint8         DisassociateReason;
  uint8         TxIndirect;
  ZMacSec_t     Sec;
} ZMacDisassociateReq_t;

/* Rx enable confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
} ZMacRxEnableCnf_t;

/* SCAN */
/* Scan request type */
typedef struct
{
  uint32         ScanChannels;
  uint8          ScanType;			
  uint8          ScanDuration;
  uint8          ChannelPage;
  uint8          MaxResults;
  ZMacSec_t      Sec;
  union
  {
    uint8        *pEnergyDetect;
    ZMacPanDesc_t *pPanDescriptor;
  }Result;
} ZMacScanReq_t;

/* Scan confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint8          ScanType;
  uint8          ChannelPage;
  uint32		     UnscannedChannels;
  uint8          ResultListSize;
  union
  {
    uint8         *pEnergyDetect;
    ZMacPanDesc_t *pPanDescriptor;
  }Result;
} ZMacScanCnf_t;


/* START */
/* Start request type */
typedef struct
{
  uint32        StartTime;
  uint16        PANID;
  uint8         LogicalChannel;
  uint8         ChannelPage;
  uint8         BeaconOrder;
  uint8         SuperframeOrder;
  uint8         PANCoordinator;
  uint8         BatteryLifeExt;
  uint8         CoordRealignment;
  ZMacSec_t     RealignSec;
  ZMacSec_t     BeaconSec;
} ZMacStartReq_t;

/* Start confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
} ZMacStartCnf_t;

/* POLL */
/* Roll request type */
typedef struct
{
  zAddrType_t CoordAddress;
  uint16      CoordPanId;
  ZMacSec_t   Sec;
} ZMacPollReq_t;

/* Poll confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
} ZMacPollCnf_t;

/* MAC_MLME_POLL_IND type */
typedef struct
{
  ZMacEventHdr_t  hdr;
  uint16          srcShortAddr;   /* Short address of the device sending the data request */
  uint16          srcPanId;       /* Pan ID of the device sending the data request */
} ZMacPollInd_t;

/* ORPHAN */
/* Orphan response type */
typedef struct
{
  ZLongAddr_t    OrphanAddress;
  uint16         ShortAddress;
  uint8          AssociatedMember;
  ZMacSec_t      Sec;
} ZMacOrphanRsp_t;

/* Orphan indication type */
typedef struct
{
  ZMacEventHdr_t hdr;
  ZLongAddr_t    OrphanAddress;
  ZMacSec_t      Sec;
} ZMacOrphanInd_t;

#if defined (MT_MAC_FUNC) || defined (MT_MAC_CB_FUNC)

/* Sync loss indication type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint16         PANId;
  uint8          LogicalChannel;
  uint8          ChannelPage;
  ZMacSec_t      Sec;
} ZMacSyncLossInd_t;

/* Data indication parameters type */
typedef struct
{
  ZMacEventHdr_t hdr;
  ZMacSec_t      Sec;
  zAddrType_t    SrcAddr;
  zAddrType_t    DstAddr;
  uint32         Timestamp;
  uint16         Timestamp2;
  uint16         SrcPANId;
  uint16         DstPANId;
  uint8          mpduLinkQuality;
  uint8          Correlation;
  uint8          Rssi;
  uint8          Dsn;
  uint8          msduLength;
  uint8         *msdu;
} ZMacDataInd_t;

/* Disassociate indication type */
typedef struct
{
  ZMacEventHdr_t hdr;
  ZLongAddr_t    DeviceAddress;
  uint8          DisassociateReason;
  ZMacSec_t      Sec;
} ZMacDisassociateInd_t;

/* Disassociate confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
  zAddrType_t    DeviceAddress;
  uint16         panID;
} ZMacDisassociateCnf_t;

/* Beacon notify indication type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint8          BSN;
  ZMacPanDesc_t *pPanDesc;
  uint8          PendAddrSpec;
  uint8         *AddrList;
  uint8          sduLength;
  uint8         *sdu;
} ZMacBeaconNotifyInd_t;

/* Purge confirm type */
typedef struct
{
  ZMacEventHdr_t hdr;
  uint8          msduHandle;
} ZMacPurgeCnf_t;
#endif

typedef enum
{
  TX_PWR_MINUS_22 = -22,
  TX_PWR_MINUS_21,
  TX_PWR_MINUS_20,
  TX_PWR_MINUS_19,
  TX_PWR_MINUS_18,
  TX_PWR_MINUS_17,
  TX_PWR_MINUS_16,
  TX_PWR_MINUS_15,
  TX_PWR_MINUS_14,
  TX_PWR_MINUS_13,
  TX_PWR_MINUS_12,
  TX_PWR_MINUS_11,
  TX_PWR_MINUS_10,
  TX_PWR_MINUS_9,
  TX_PWR_MINUS_8,
  TX_PWR_MINUS_7,
  TX_PWR_MINUS_6,
  TX_PWR_MINUS_5,
  TX_PWR_MINUS_4,
  TX_PWR_MINUS_3,
  TX_PWR_MINUS_2,
  TX_PWR_MINUS_1,
  TX_PWR_ZERO,
  TX_PWR_PLUS_1,
  TX_PWR_PLUS_2,
  TX_PWR_PLUS_3,
  TX_PWR_PLUS_4,
  TX_PWR_PLUS_5,
  TX_PWR_PLUS_6,
  TX_PWR_PLUS_7,
  TX_PWR_PLUS_8,
  TX_PWR_PLUS_9,
  TX_PWR_PLUS_10,
  TX_PWR_PLUS_11,
  TX_PWR_PLUS_12,
  TX_PWR_PLUS_13,
  TX_PWR_PLUS_14,
  TX_PWR_PLUS_15,
  TX_PWR_PLUS_16,
  TX_PWR_PLUS_17,
  TX_PWR_PLUS_18,
  TX_PWR_PLUS_19
} ZMacTransmitPower_t;  // The transmit power in units of -1 dBm.

typedef struct
{
  byte protocolID;
  byte stackProfile;    // 4 bit in native
  byte protocolVersion; // 4 bit in native
  byte reserved;        // 2 bit in native
  byte routerCapacity;  // 1 bit in native
  byte deviceDepth;     // 4 bit in native
  byte deviceCapacity;  // 1 bit in native
  byte extendedPANID[Z_EXTADDR_LEN];
  byte txOffset[3];
  byte updateId;
} beaconPayload_t;

typedef uint8 (*applySecCB_t)( uint8 len, uint8 *msdu );

typedef enum
{
  LQI_ADJ_OFF = 0,
  LQI_ADJ_MODE1,
  LQI_ADJ_MODE2,
  LQI_ADJ_GET = 0xFF
} ZMacLqiAdjust_t;  // Mode settings for lqi adjustment

#define NWK_CMD_ID_LEN sizeof( byte )

  extern ZMacStatus_t ZMacInit( void );

  extern ZMacStatus_t ZMacDataReq( ZMacDataReq_t *param );

  extern uint8 ZMacDataReqSec( ZMacDataReq_t *pData, applySecCB_t secCB );

  extern ZMacStatus_t ZMacAssociateReq( ZMacAssociateReq_t *param );

  extern ZMacStatus_t ZMacAssociateRsp( ZMacAssociateRsp_t *param );

  extern ZMacStatus_t ZMacDisassociateReq( ZMacDisassociateReq_t *param );

  extern byte ZMacUpdate( void );

  extern ZMacStatus_t ZMacGetReq( ZMacAttributes_t attr, byte *value );

  extern ZMacStatus_t ZMacOrphanRsp( ZMacOrphanRsp_t *param );

  extern ZMacStatus_t ZMacPollReq( ZMacPollReq_t *param );

  extern ZMacStatus_t ZMacReset( byte SetDefaultPIB );

  extern ZMacStatus_t ZMacScanReq( ZMacScanReq_t *param );

  extern ZMacStatus_t ZMacSetReq( ZMacAttributes_t attr, byte *value );

#ifdef MAC_SECURITY
  
  extern ZMacStatus_t ZMacSecurityGetReq( ZMacAttributes_t attr, byte *value );

  extern ZMacStatus_t ZMacSecuritySetReq( ZMacAttributes_t attr, byte *value );
#endif /* MAC_SECURITY */

  extern ZMacStatus_t ZMacStartReq( ZMacStartReq_t *param );

  extern ZMacStatus_t ZMacSyncReq( ZMacSyncReq_t *param );

  extern ZMacStatus_t ZMacCleanReq( void );

  extern ZMacStatus_t ZMacPurgeReq( byte msduHandle );

  extern ZMacStatus_t ZMacSrcMatchEnable (uint8 addrType, uint8 numEntries);

  extern ZMacStatus_t ZMacSrcMatchAddEntry (zAddrType_t *addr, uint16 panID);

  extern ZMacStatus_t ZMacSrcMatchDeleteEntry (zAddrType_t *addr, uint16 panID);

  extern ZMacStatus_t ZMacSrcMatchAckAllPending (uint8 option);

  extern ZMacStatus_t ZMacSrcMatchCheckAllPending (void);

  extern void ZMacPwrOnReq ( void );

  extern uint8 ZMac_PwrMode(void);

  extern ZMacStatus_t ZMacSetTransmitPower( ZMacTransmitPower_t level );

  extern void ZMacSendNoData( uint16 DstAddr, uint16 DstPANId );

  extern uint8 (*pZMac_AppCallback)( uint8 *msgPtr );

  extern uint8 ZMacStateIdle( void );

  extern ZMacLqiAdjust_t ZMacLqiAdjustMode( ZMacLqiAdjust_t mode );

#ifdef __cplusplus
}
#endif

#endif /* ZMAC_H */

zmac_cb.c

#include "ZComDef.h"
#include "OSAL.h"
#include "ZMAC.h"
#include "MT_MAC.h"
#include "hal_mcu.h"

#if !defined NONWK
#include "nwk.h"
#include "nwk_bufs.h"
#include "ZGlobals.h"
#endif

#if defined( MACSIM )
  #include "mac_sim.h"
#endif

#include "mac_security.h"

#include "mac_main.h"
extern void *ZMac_ScanBuf;


#if !defined NONWK
/* Lookup table for size of structures. Must match with the order of MAC callback events */
const uint8 CODE zmacCBSizeTable [] = {
  0,
  sizeof(ZMacAssociateInd_t),       // MAC_MLME_ASSOCIATE_IND      1   Associate indication
  sizeof(ZMacAssociateCnf_t),       // MAC_MLME_ASSOCIATE_CNF      2   Associate confirm
  0,                                // MAC_MLME_DISASSOCIATE_IND   3   Disassociate indication
  0,                                // MAC_MLME_DISASSOCIATE_CNF   4   Disassociate confirm
  sizeof(macMlmeBeaconNotifyInd_t), // MAC_MLME_BEACON_NOTIFY_IND  5   con notify indication
  sizeof(ZMacOrphanInd_t),          // MAC_MLME_ORPHAN_IND         6   Orphan indication
  sizeof(ZMacScanCnf_t),            // MAC_MLME_SCAN_CNF           7   Scan confirm
  sizeof(ZMacStartCnf_t),           // MAC_MLME_START_CNF          8   Start confirm
  0,                                // MAC_MLME_SYNC_LOSS_IND      9   Sync loss indication
  sizeof(ZMacPollCnf_t),            // MAC_MLME_POLL_CNF           10  Poll confirm
  sizeof(ZMacCommStatusInd_t),      // MAC_MLME_COMM_STATUS_IND    11  Comm status indication
  sizeof(ZMacDataCnf_t),            // MAC_MCPS_DATA_CNF           12  Data confirm
  sizeof(macMcpsDataInd_t),         // MAC_MCPS_DATA_IND           13  Data indication
  0,                                // MAC_MCPS_PURGE_CNF          14  Purge confirm
  0,                                // MAC_PWR_ON_CNF              15  Power on confirm
  sizeof(ZMacPollInd_t)             // MAC_MLME_POLL_IND           16  Poll indication
};
#endif /* !defined NONWK */

/* LQI Adjustment Mode */
static ZMacLqiAdjust_t lqiAdjMode = LQI_ADJ_OFF;

#if !defined NONWK
/* LQI Adjustment Function */
static void ZMacLqiAdjust( uint8 corr, uint8* lqi );
#endif

uint8 (*pZMac_AppCallback)( uint8 *msgPtr ) = (void*)NULL;


void MAC_CbackEvent(macCbackEvent_t *pData)
#ifndef MT_MAC_CB_FUNC
{
#if !defined NONWK
  uint8 event = pData->hdr.event;
  uint16 tmp = zmacCBSizeTable[event];
  macCbackEvent_t *msgPtr;

  /* If the Network layer will handle a new MAC callback, a non-zero value must be entered in the
   * corresponding location in the zmacCBSizeTable[] - thus the table acts as "should handle"?
   */
  if (tmp == 0)
  {
    return;
  }

  // MAC_MCPS_DATA_IND is very special - it is the only event where the MAC does not free *pData.
  if ( event == MAC_MCPS_DATA_IND )
  {
    MAC_MlmeGetReq( MAC_SHORT_ADDRESS, &tmp );
    if ((tmp == INVALID_NODE_ADDR) || (tmp == NWK_BROADCAST_SHORTADDR_DEVALL) ||
        (pData->dataInd.msdu.len == 0))
    {
      mac_msg_deallocate( (uint8 **)&pData );
      return;
    }
    msgPtr = pData;
  }
  else
  {
    if (event == MAC_MLME_BEACON_NOTIFY_IND )
    {
      tmp += sizeof(macPanDesc_t) + pData->beaconNotifyInd.sduLength;
    }
    else if (event == MAC_MLME_SCAN_CNF)
    {
      if (pData->scanCnf.scanType == ZMAC_ED_SCAN)
      {
        tmp += ZMAC_ED_SCAN_MAXCHANNELS;
      }
      else
      {
        tmp += sizeof( ZMacPanDesc_t ) * pData->scanCnf.resultListSize;
      }
    }

    if ( !(msgPtr = (macCbackEvent_t *)osal_msg_allocate(tmp)) )
    {
      // Not enough memory. If data confirm - try again
      if ((event == MAC_MCPS_DATA_CNF) && (pData->dataCnf.pDataReq != NULL))
      {
        halIntState_t intState;

        // This is not normally deallocated here because the pZMac_AppCallback()
        // application may need it.
        HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

        mac_msg_deallocate( (uint8**)&(pData->dataCnf.pDataReq) );
        if ( !(msgPtr = (macCbackEvent_t *)osal_msg_allocate(tmp)) )
        {
          // Still no allocation, something is wrong
          HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
          return;
        }
        HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
      }
      else
      {
        // This message is dropped
        return;
      }
    }
    osal_memcpy(msgPtr, pData, zmacCBSizeTable[event]);
  }

  if ( event == MAC_MLME_BEACON_NOTIFY_IND )
  {
    macMlmeBeaconNotifyInd_t *pBeacon = (macMlmeBeaconNotifyInd_t*)msgPtr;

    osal_memcpy(pBeacon+1, pBeacon->pPanDesc, sizeof(macPanDesc_t));
    pBeacon->pPanDesc = (macPanDesc_t *)(pBeacon+1);
    osal_memcpy(pBeacon->pPanDesc+1, pBeacon->pSdu, pBeacon->sduLength);
    pBeacon->pSdu = (uint8 *)(pBeacon->pPanDesc+1);
  }
  else if (event == MAC_MLME_SCAN_CNF)
  {
    macMlmeScanCnf_t *pScan = (macMlmeScanCnf_t*)msgPtr;

    if (ZMac_ScanBuf != NULL)
    {
      void *pTmp = ZMac_ScanBuf;
      ZMac_ScanBuf = NULL;

      if (pScan->scanType == ZMAC_ED_SCAN)
      {
        pScan->result.pEnergyDetect = (uint8*) (pScan + 1);
        osal_memcpy(pScan->result.pEnergyDetect, pTmp, ZMAC_ED_SCAN_MAXCHANNELS);
      }
      else
      {
        pScan->result.pPanDescriptor = (macPanDesc_t*) (pScan + 1);
        osal_memcpy(pScan + 1, pTmp, sizeof( ZMacPanDesc_t ) * pScan->resultListSize);
      }

      osal_mem_free(pTmp);
    }
  }

  if ( ( pZMac_AppCallback == NULL ) || ( pZMac_AppCallback( (uint8 *)msgPtr ) == FALSE ) )
  {
    // Filter out non-zigbee packets
    if ( event == MAC_MCPS_DATA_IND )
    {
      uint8 fcFrameType = (pData->dataInd.msdu.p[0] & 0x03);
      uint8 fcProtoVer = ((pData->dataInd.msdu.p[0] >> 2) & 0x0F);
      uint8 fcReserve = (pData->dataInd.msdu.p[1] & 0xE0);
      if ( (fcFrameType > 0x01) || (fcProtoVer != _NIB.nwkProtocolVersion) || (fcReserve != 0)
          || (pData->dataInd.mac.srcAddr.addrMode != SADDR_MODE_SHORT) )
      {
        // Drop the message
        mac_msg_deallocate( (uint8 **)&pData );
        return;
      }
      else
      {
        macDataInd_t *pInd = &msgPtr->dataInd.mac;
        // See if LQI needs adjustment due to frame correlation
        ZMacLqiAdjust( pInd->correlation, &pInd->mpduLinkQuality );

        // Look for broadcast message that has a radius of greater 1
        if ( (pData->dataInd.mac.dstAddr.addr.shortAddr == 0xFFFF)
               && (pData->dataInd.msdu.p[6] > 1) )
        {
          // Send the messsage to a special broadcast queue
          if ( nwk_broadcastSend( (uint8 *)msgPtr ) != SUCCESS )
          {
            // Drop the message, too many broadcast messages to process
            mac_msg_deallocate( (uint8 **)&pData );
          }
          return;
        }
      }
    }
    else if ((event == MAC_MCPS_DATA_CNF) && (pData->hdr.status != MAC_NO_RESOURCES))
    {
      macMcpsDataCnf_t *pCnf = &msgPtr->dataCnf;
      
      if (pCnf->pDataReq->internal.txOptions & MAC_TXOPTION_ACK)
      {
        // See if LQI needs adjustment due to frame correlation
        ZMacLqiAdjust( pCnf->correlation, &pCnf->mpduLinkQuality );
      }
    }

    // Application hasn't already processed this message. Send it to NWK task.
    osal_msg_send( NWK_TaskID, (uint8 *)msgPtr );
  }

  if ((event == MAC_MCPS_DATA_CNF) && (pData->dataCnf.pDataReq != NULL))
  {
    // If the application needs 'pDataReq' then we cannot free it here.
    // The application must free it after using it. Note that 'pDataReq'
    // is of macMcpsDataReq_t (and not ZMacDataReq_t) type.

    mac_msg_deallocate( (uint8**)&(pData->dataCnf.pDataReq) );
  }
#endif
}
#else  // ifdef MT_MAC_CB_FUNC
{
  /* Check if MT has subscribed for this callback If so, pass it as an event to MonitorTest */
  switch (pData->hdr.event)
  {
    case MAC_MLME_ASSOCIATE_IND:
      if ( _macCallbackSub & CB_ID_NWK_ASSOCIATE_IND )
        nwk_MTCallbackSubNwkAssociateInd ( (ZMacAssociateInd_t *)pData );
      break;

    case MAC_MLME_ASSOCIATE_CNF:
      if ( _macCallbackSub & CB_ID_NWK_ASSOCIATE_CNF )
        nwk_MTCallbackSubNwkAssociateCnf ( (ZMacAssociateCnf_t *)pData );
      break;

    case MAC_MLME_DISASSOCIATE_IND:
      if ( _macCallbackSub & CB_ID_NWK_DISASSOCIATE_IND )
        nwk_MTCallbackSubNwkDisassociateInd ( (ZMacDisassociateInd_t *)pData );
      break;

    case MAC_MLME_DISASSOCIATE_CNF:
      if ( _macCallbackSub & CB_ID_NWK_DISASSOCIATE_CNF )
        nwk_MTCallbackSubNwkDisassociateCnf ( (ZMacDisassociateCnf_t *)pData );
      break;

    case MAC_MLME_BEACON_NOTIFY_IND:
      if ( _macCallbackSub & CB_ID_NWK_BEACON_NOTIFY_IND )
        nwk_MTCallbackSubNwkBeaconNotifyInd( (ZMacBeaconNotifyInd_t *)pData );
      break;

    case MAC_MLME_ORPHAN_IND:
      if ( _macCallbackSub & CB_ID_NWK_ORPHAN_IND )
        nwk_MTCallbackSubNwkOrphanInd( (ZMacOrphanInd_t *) pData );
      break;

    case MAC_MLME_SCAN_CNF:
      if ( _macCallbackSub & CB_ID_NWK_SCAN_CNF )
      {
        pData->scanCnf.result.pEnergyDetect = ZMac_ScanBuf;
        nwk_MTCallbackSubNwkScanCnf ( (ZMacScanCnf_t *) pData );
      }

      if (ZMac_ScanBuf != NULL)
      {
        void *pTmp = ZMac_ScanBuf;
        ZMac_ScanBuf = NULL;
        osal_mem_free(pTmp);
      }
      break;

    case MAC_MLME_START_CNF:
      if ( _macCallbackSub & CB_ID_NWK_START_CNF )
        nwk_MTCallbackSubNwkStartCnf ( pData->hdr.status );
      break;

    case MAC_MLME_SYNC_LOSS_IND:
      if ( _macCallbackSub & CB_ID_NWK_SYNC_LOSS_IND )
       nwk_MTCallbackSubNwkSyncLossInd( (ZMacSyncLossInd_t *) pData );
      break;

    case MAC_MLME_POLL_CNF:
      if ( _macCallbackSub & CB_ID_NWK_POLL_CNF )
         nwk_MTCallbackSubNwkPollCnf( pData->hdr.status );
      break;

    case MAC_MLME_COMM_STATUS_IND:
      if ( _macCallbackSub & CB_ID_NWK_COMM_STATUS_IND )
        nwk_MTCallbackSubCommStatusInd ( (ZMacCommStatusInd_t *) pData );
      break;

    case MAC_MCPS_DATA_CNF:
      if (pData->dataCnf.pDataReq != NULL)
        mac_msg_deallocate((uint8**)&pData->dataCnf.pDataReq);

      if ( _macCallbackSub & CB_ID_NWK_DATA_CNF )
        nwk_MTCallbackSubNwkDataCnf( (ZMacDataCnf_t *) pData );
      break;

    case MAC_MCPS_DATA_IND:
      {
        /*
           Data Ind is unconventional: to save an alloc/copy, reuse the MAC
           buffer and re-organize the contents into ZMAC format.
        */
        ZMacDataInd_t *pDataInd = (ZMacDataInd_t *) pData;
        uint8 event, status, len, *msdu;

        /* Store parameters */
        event = pData->hdr.event;
        status = pData->hdr.status;
        len = pData->dataInd.msdu.len;
        msdu = pData->dataInd.msdu.p;

        /* Copy security fields */
        osal_memcpy(&pDataInd->Sec, &pData->dataInd.sec, sizeof(ZMacSec_t));
        
        /* Copy mac fields one by one since the two buffers overlap. */
        osal_memcpy(&pDataInd->SrcAddr, &pData->dataInd.mac.srcAddr, sizeof(zAddrType_t));
        osal_memcpy(&pDataInd->DstAddr, &pData->dataInd.mac.dstAddr, sizeof(zAddrType_t));
        pDataInd->Timestamp = pData->dataInd.mac.timestamp;
        pDataInd->Timestamp2 = pData->dataInd.mac.timestamp2;
        pDataInd->SrcPANId = pData->dataInd.mac.srcPanId;
        pDataInd->DstPANId = pData->dataInd.mac.dstPanId;
        pDataInd->mpduLinkQuality = pData->dataInd.mac.mpduLinkQuality;
        pDataInd->Correlation = pData->dataInd.mac.correlation;
        pDataInd->Rssi = pData->dataInd.mac.rssi;
        pDataInd->Dsn = pData->dataInd.mac.dsn;

        /* Restore parameters */
        pDataInd->hdr.Status = status;
        pDataInd->hdr.Event = event;
        pDataInd->msduLength = len;

        if (len)
          pDataInd->msdu = msdu;
        else
          pDataInd->msdu = NULL;

        if ( _macCallbackSub & CB_ID_NWK_DATA_IND )
          nwk_MTCallbackSubNwkDataInd ( pDataInd );
      }

      /* free buffer */
      mac_msg_deallocate( (uint8 **)&pData );
      break;

    case MAC_MCPS_PURGE_CNF:
      if ( _macCallbackSub & CB_ID_NWK_PURGE_CNF )
        nwk_MTCallbackSubNwkPurgeCnf( (ZMacPurgeCnf_t *) pData);
      break;

    default:
      break;
  }
}
#endif

uint8 MAC_CbackCheckPending(void)
{
#if !defined (NONWK)
  if ( ZSTACK_ROUTER_BUILD )
  {
    return (nwkDB_ReturnIndirectHoldingCnt());
  }
  else
  {
    return (0);
  }
#else
  return (0);
#endif
}

ZMacLqiAdjust_t ZMacLqiAdjustMode( ZMacLqiAdjust_t mode )
{
  if ( mode != LQI_ADJ_GET )
  {
    lqiAdjMode = mode;
  }
  return ( lqiAdjMode );
}

#if !defined NONWK

static void ZMacLqiAdjust( uint8 corr, uint8 *lqi )
{
  if ( lqiAdjMode != LQI_ADJ_OFF )
  {
    uint16 adjLqi = *lqi;

    // Keep correlation within theoretical limits
    if ( corr < LQI_CORR_MIN )
    {
       corr = LQI_CORR_MIN;
    }
    else if ( corr > LQI_CORR_MAX )
    {
       corr = LQI_CORR_MAX;
    }

    if ( lqiAdjMode == LQI_ADJ_MODE1 )
    {
      /* MODE1 - linear scaling of incoming LQI with a "correlation percentage"
                 which is computed from the incoming correlation value between
                 theorectical minimum/maximum values. This is a very simple way
                 of 'derating' the incoming LQI as correlation value drops. */
      adjLqi = (adjLqi * (corr - LQI_CORR_MIN)) / (LQI_CORR_MAX - LQI_CORR_MIN);
    }
    else if ( lqiAdjMode == LQI_ADJ_MODE2 )
    {
      /* MODE2 - location for developer to implement a proprietary algorithm */
    }

    // Replace incoming LQI with scaled value
    *lqi = (adjLqi > 255) ? 255 : (uint8)adjLqi;
  }
}
#endif

zmac_intermal.h

#ifndef ZMAC_INTERNAL_H
#define ZMAC_INTERNAL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "mac_api.h"

// MAC Type Indication
#define ZMAC_F8W

// PHY transiver output power values
#define OUTPUT_POWER_0DBM       0x00
#define OUTPUT_POWER_N1DBM      0x21
#define OUTPUT_POWER_N3DBM      0x23
#define OUTPUT_POWER_N5DBM      0x25
#define OUTPUT_POWER_N7DBM      0x27
#define OUTPUT_POWER_N10DBM     0x2A
#define OUTPUT_POWER_N15DBM     0x2F
#define OUTPUT_POWER_N25DBM     0x39

// MAC PIB Attributes
enum
{
  ZMacAckWaitDuration                   = MAC_ACK_WAIT_DURATION,
  ZMacAssociationPermit                 = MAC_ASSOCIATION_PERMIT,
  ZMacAutoRequest                       = MAC_AUTO_REQUEST,
  ZMacBattLifeExt                       = MAC_BATT_LIFE_EXT,
  ZMacBattLeftExtPeriods                = MAC_BATT_LIFE_EXT_PERIODS,

  ZMacBeaconMSDU                        = MAC_BEACON_PAYLOAD,
  ZMacBeaconMSDULength                  = MAC_BEACON_PAYLOAD_LENGTH,
  ZMacBeaconOrder                       = MAC_BEACON_ORDER,
  ZMacBeaconTxTime                      = MAC_BEACON_TX_TIME,
  ZMacBSN                               = MAC_BSN,

  ZMacCoordExtendedAddress              = MAC_COORD_EXTENDED_ADDRESS,
  ZMacCoordShortAddress                 = MAC_COORD_SHORT_ADDRESS,
  ZMacDSN                               = MAC_DSN,
  ZMacGTSPermit                         = MAC_GTS_PERMIT,
  ZMacMaxCSMABackoffs                   = MAC_MAX_CSMA_BACKOFFS,

  ZMacMinBE                             = MAC_MIN_BE,
  ZMacPanId                             = MAC_PAN_ID,
  ZMacPromiscuousMode                   = MAC_PROMISCUOUS_MODE,
  ZMacRxOnIdle                          = MAC_RX_ON_WHEN_IDLE,
  ZMacShortAddress                      = MAC_SHORT_ADDRESS,

  ZMacSuperframeOrder                   = MAC_SUPERFRAME_ORDER,
  ZMacTransactionPersistenceTime        = MAC_TRANSACTION_PERSISTENCE_TIME,
  ZMacAssociatedPanCoord                = MAC_ASSOCIATED_PAN_COORD,
  ZMacMaxBE                             = MAC_MAX_BE,
  ZMacMaxFrameTotalWaitTime             = MAC_MAX_FRAME_TOTAL_WAIT_TIME,

  ZMacMaxFrameRetries                   = MAC_MAX_FRAME_RETRIES,
  ZMacResponseWaitTime                  = MAC_RESPONSE_WAIT_TIME,
  ZMacSyncSymbolOffset                  = MAC_SYNC_SYMBOL_OFFSET,
  ZMacTimestampSupported                = MAC_TIMESTAMP_SUPPORTED,
  ZMacSecurityEnabled                   = MAC_SECURITY_ENABLED,

  // Proprietary Items
  ZMacPhyTransmitPower                  = MAC_PHY_TRANSMIT_POWER,
  ZMacChannel                           = MAC_LOGICAL_CHANNEL,
  ZMacExtAddr                           = MAC_EXTENDED_ADDRESS,
  ZMacAltBE                             = MAC_ALT_BE,
  ZMacDeviceBeaconOrder                 = MAC_DEVICE_BEACON_ORDER,
  ZMacPhyTransmitPowerSigned            = MAC_PHY_TRANSMIT_POWER_SIGNED,

#ifdef MAC_SECURITY
  ZMacKeyTable                          = MAC_KEY_TABLE,
  ZMacKeyTableEntries                   = MAC_KEY_TABLE_ENTRIES,
  ZMacDeviceTable                       = MAC_DEVICE_TABLE,
  ZMacDeviceTableEntries                = MAC_DEVICE_TABLE_ENTRIES,
  ZMacSecurityLevelTable                = MAC_SECURITY_LEVEL_TABLE,

  ZMacSecurityLevelTableEntries         = MAC_SECURITY_LEVEL_TABLE_ENTRIES,
  ZMacFrameCounter                      = MAC_FRAME_COUNTER,
  ZMacAutoRequestSecurityLevel          = MAC_AUTO_REQUEST_SECURITY_LEVEL,
  ZMacAutoRequestKeyIdMode              = MAC_AUTO_REQUEST_KEY_ID_MODE,
  ZMacAutoRequestKeySource              = MAC_AUTO_REQUEST_KEY_SOURCE,

  ZMacAutoRequestKeyIndex               = MAC_AUTO_REQUEST_KEY_INDEX,
  ZMacDefaultKeySource                  = MAC_DEFAULT_KEY_SOURCE,
  ZMacPanCoordExtendedAddress           = MAC_PAN_COORD_EXTENDED_ADDRESS,
  ZMacPanCoordShortAddress              = MAC_PAN_COORD_SHORT_ADDRESS,
#endif /* MAC_SECURITY */

  // Junk
  ZMacACLDefaultSecurityMaterialLength  = 0,     // not implemented
  ZMacTxGTSId                           = 1,     // not implemented
  ZMacUpperLayerType                    = 2,     // not implemented
  ZMacRxGTSId                           = 3,     // not implemented
  ZMacSnoozePermit                      = 4      // not implemented
};

typedef uint8 ZMacAttributes_t;

// Status type
typedef uint8 ZMacStatus_t;

/* Definition of scan type */
#define ZMAC_ED_SCAN                   MAC_SCAN_ED
#define ZMAC_ACTIVE_SCAN               MAC_SCAN_ACTIVE
#define ZMAC_PASSIVE_SCAN              MAC_SCAN_PASSIVE
#define ZMAC_ORPHAN_SCAN               MAC_SCAN_ORPHAN

// Association Status Field Values
#define ZMAC_SUCCESSFUL_ASSOCIATION    0x00
#define ZMAC_PAN_AT_CAPACITY           0x01
#define ZMAC_PAN_ACCESS_DENIED         0x02

// Disassociation Reason Codes
#define ZMAC_COORD_INITIATE            MAC_DISASSOC_COORD
#define ZMAC_DEVICE_INITIATE           MAC_DISASSOC_DEVICE

#define ZMAC_SECURITY_USE              0x01
#define ZMAC_ACL_ENTRY                 0x02
#define ZMAC_SECURITY_FAILURE          0x04

// TX Option flags
#define ZMAC_TXOPTION_ACK              MAC_TXOPTION_ACK
#define ZMAC_TXOPTION_GTS              MAC_TXOPTION_GTS
#define ZMAC_TXOPTION_INDIRECT         MAC_TXOPTION_INDIRECT
#define ZMAC_TXOPTION_SECURITY_ENABLE  MAC_TXOPTION_SECURITY
#define ZMAC_TXOPTION_NO_RETRANS       MAC_TXOPTION_NO_RETRANS
#define ZMAC_TXOPTION_NO_CNF           MAC_TXOPTION_NO_CNF

#define ZMAC_ASSOC_CAPINFO_FFD_TYPE    MAC_CAPABLE_FFD
#define ZMAC_ASSOC_CAPINFO_RX_ON_IDLE  MAC_CAPABLE_RX_ON_IDLE
#define ZMAC_ASSOC_CAPINFO_SECURITY    MAC_CAPABLE_SECURITY

// LQI to Cost mapping
#define MIN_LQI_COST_1  12     //24
#define MIN_LQI_COST_2  9      //20
#define MIN_LQI_COST_3  6      //16
#define MIN_LQI_COST_4  4      //12
#define MIN_LQI_COST_5  2      //8
#define MIN_LQI_COST_6  1      //4
#define MIN_LQI_COST_7  0      //0

/* Number of bytes to allocate for ED scan; matches ED_SCAN_MAXCHANNELS in nwk.h */
#define ZMAC_ED_SCAN_MAXCHANNELS       27

#define ZMAC_SUCCESS                   MAC_SUCCESS
#define ZMAC_TRANSACTION_OVERFLOW      MAC_TRANSACTION_OVERFLOW
#define ZMAC_TRANSACTION_EXPIRED       MAC_TRANSACTION_EXPIRED
#define ZMAC_CHANNEL_ACCESS_FAILURE    MAC_CHANNEL_ACCESS_FAILURE
#define ZMAC_NO_RESOURCES              MAC_NO_RESOURCES

#define ZMAC_KEY_SOURCE_MAX_LEN        MAC_KEY_SOURCE_MAX_LEN

#ifdef __cplusplus
}
#endif

#endif /* ZMAC_INTERNAL_H */

ZMain(主函数)

chipcom_cstartup.s51

#include "iar_common.h"

	PROGRAM	CSTARTUP
	PUBLIC  __program_start

	EXTERN  ?B0
	EXTERNS_FOR_ALL_DPTR_SYMBOLS()
	REQUIRE ?B0
   REQUIRE __call_main

#if (__NUMBER_OF_DPTRS__ > 1)
	REQUIRE ?RESET_DPS
#endif

#if (__CORE__ == __CORE_EXTENDED1__)
   REQUIRE __call_init_extended1
#endif

   ; Uncomment this when rom-monitor requires 3 NOPS between statements.
   ; REQUIRE ?ROM_MONITOR_NOPS

   RSEG	REGISTERS:NOROOT:DATA
   PUBLIC  ?REGISTERS

?REGISTERS:

   RSEG	ISTACK:NOROOT:IDATA
   PUBLIC  ?ISTACK_START
?ISTACK_START:

   RSEG	PSTACK:NOROOT:XDATA
   PUBLIC  ?PSTACK_START
?PSTACK_START:

   RSEG	XSTACK:NOROOT:XDATA
   PUBLIC  ?XSTACK_START
?XSTACK_START:

   RSEG	EXT_STACK:NOROOT:XDATA
   PUBLIC  ?EXT_STACK_START
?EXT_STACK_START:


   COMMON   INTVEC:CODE:ROOT(0)

?reset_vector:
   DB	0x02    ; LJMP
#if defined(START_INIT_IN_FAR)
   DB	BYTE3(__program_start)
#endif
   DB	high(__program_start)
   DB	low(__program_start)

   RSEG    CSTART:CODE:ROOT
   EXTERN  ?REGISTER_BANK
   REQUIRE ?ISTACK_START
   REQUIRE ?REGISTERS
   REQUIRE ?reset_vector

__program_start:
   MOV     PSW,#(?REGISTER_BANK << 3)

#if (defined(__EXTENDED_STACK__) )

   PUBLIC  ?RESET_ESP
   REQUIRE ?EXT_STACK_START
   EXTERN	?ESP

?RESET_ESP:
   MOV     SP,#low(sfb(EXT_STACK))
   MOV     ?ESP,#high(sfb(EXT_STACK))
#else


   PUBLIC  ?RESET_SP
   REQUIRE ?ISTACK_START

?RESET_SP:
   MOV     SP,#SFB(ISTACK)
#endif


   RSEG	CSTART:CODE:NOROOT
   PUBLIC  ?RESET_PSP
   EXTERN  ?PSP
   REQUIRE ?PSTACK_START
   REQUIRE ?RESET_PDATA_BANK
   EXTERN  ?PSTACK

?RESET_PSP:
   MOV     ?PSP,#low(sfe(PSTACK))

   RSEG	CSTART:CODE:NOROOT
   PUBLIC  ?RESET_XSP
   EXTERN  ?XSP
   REQUIRE ?XSTACK_START
   EXTERN  ?XSTACK

?RESET_XSP:
   MOV     ?XSP,#low(sfe(XSTACK))
   MOV     ?XSP+1,#high(sfe(XSTACK))

#if ( (__CODE_MODEL__ == __CM_BANKED__) || ( __CODE_MODEL__ == __CM_NEAR__ ) )
   RSEG	CSTART:CODE:NOROOT
   PUBLIC  ?RESET_CODE_BANK
   EXTERN  ?CBANK

?RESET_CODE_BANK:
   NOP
//	MOV	?CBANK,#0x00
#endif

   RSEG	CSTART:CODE:NOROOT
   PUBLIC  ?RESET_PDATA_BANK
   EXTERN  ?PBANK
   EXTERN	?PBANK_NUMBER

?RESET_PDATA_BANK:
   MOV     ?PBANK,#?PBANK_NUMBER
#if (defined ( __EXTENDED_DPTR__))
   EXTERN  ?PBANK_EXT

?RESET_PDATA_BANK_EXT:
   MOV     ?PBANK_EXT,#0x00
#endif


#if (__NUMBER_OF_DPTRS__ > 1)

   RSEG	CSTART:CODE:NOROOT
   PUBLIC  ?RESET_DPS
   EXTERN  ?DPS

?RESET_DPS:
   MOV	?DPS,#0x00

#endif

#if (__CORE__ == __CORE_EXTENDED1__)

   REQUIRE __call_init_extended1

   RSEG	CSTART:CODE:NOROOT
   PUBLIC  __call_init_extended1
   EXTERN	__init_extended1


__call_init_extended1:
   DB	0x12    ; LCALL
#if defined(START_INIT_IN_FAR)
   DB	BYTE3(__init_extended1)
#endif
   DB	high(__init_extended1)
   DB	low(__init_extended1)
#endif


   RSEG    CSTART:CODE:NOROOT
   EXTERN  ?cmain

__call_main:
   LJMP	?cmain

   ENDMOD

;----------------------------------------------------------------;
; Virtual registers						 ;
; =================						 ;
; Below is some segment needed for the IAR ICC C/EC++ compiler   ;
;								 ;
; BREG  : A segment for 8 bit registers for use by the compiler. ;
;         ?B0 is the first register.                             ;
; VREG  : Segement that holds up to 32 virtual registers for     ;
;         use by the compiler. ?V0 is the first register.        ;
; PSP   : Segment containing the PDATA stack pointer (?PSP)      ;
; XSP   : Segment containing the XDATA stack pointer (?XSP)      ;
; 								 ;
;----------------------------------------------------------------;
; NOTE: The XLINK varialbe _NR_OF_VIRTUAL_REGISTERS must be 	 ;
;       defined to set the size for the VREG segment.   	 ;
;----------------------------------------------------------------;

   MODULE  VIRTUAL_REGISTERS
   PUBLIC  ?B0
   PUBLIC  ?V0
   PUBLIC  ?PSP
   PUBLIC  ?XSP
   RSEG    BREG:BIT:NOROOT

?B0:
   DS      8

   RSEG    VREG:DATA:NOROOT
   EXTERN	_NR_OF_VIRTUAL_REGISTERS
?V0:
   DS      0

   RSEG    PSP:DATA:NOROOT
   EXTERN  ?RESET_PSP
   REQUIRE	?RESET_PSP
?PSP:
   DS      1

   RSEG    XSP:DATA:NOROOT
   EXTERN  ?RESET_XSP
   REQUIRE	?RESET_XSP
?XSP:
   DS      2

   ENDMOD ; VIRTUAL_REGISTERS


;----------------------------------------------------------------;
; Register banks						 ;
; =================						 ;
; Below is some segment needed for the IAR ICC C/EC++ compiler   ;
;								 ;
; The register banks will only be included if the #pragma        ;
; register_bank is used for the corresponding register bank      ;
; 								 ;
;----------------------------------------------------------------;

   MODULE	REGISTER_BANK0
   PUBLIC	__REG_BANK_0
   ASEGN	__REG_BANK0:DATA,0x00

__REG_BANK_0:
   DS	8
   ENDMOD


   MODULE	REGISTER_BANK1
   PUBLIC	__REG_BANK_1
   ASEGN	__REG_BANK1:DATA,0x08
__REG_BANK_1:
   DS	8
   ENDMOD


   MODULE	REGISTER_BANK2
   PUBLIC	__REG_BANK_2
   ASEGN	__REG_BANK2:DATA,0x10
__REG_BANK_2:
   DS	8
   ENDMOD


   MODULE	REGISTER_BANK3
   PUBLIC	__REG_BANK_3
   ASEGN	__REG_BANK3:DATA,0x18
__REG_BANK_3:
   DS	8
   ENDMOD	; REGISTER_BANK3

   END

OnBoard.c

#include "ZComDef.h"
#include "ZGlobals.h"
#include "OnBoard.h"
#include "OSAL.h"
#include "MT.h"
#include "MT_SYS.h"
#include "DebugTrace.h"

/* Hal */
#include "hal_lcd.h"
#include "hal_mcu.h"
#include "hal_timer.h"
#include "hal_key.h"
#include "hal_led.h"

/* Allow access macRandomByte() */
#include "mac_radio_defs.h"

// Task ID not initialized
#define NO_TASK_ID 0xFF

// Minimum length RAM "pattern" for Stack check
#define MIN_RAM_INIT 12


#if defined MAKE_CRC_SHDW
#pragma location="CRC_SHDW"
const CODE uint16 _crcShdw = 0xFFFF;
#pragma required=_crcShdw

#else  // if !defined MAKE_CRC_SHDW

#pragma location="LOCK_BITS_ADDRESS_SPACE"
__no_init uint8 _lockBits[16];
#pragma required=_lockBits

#if defined ZCL_KEY_ESTABLISH
#include "zcl_cert_data.c"
#else
#pragma location="IEEE_ADDRESS_SPACE"
__no_init uint8 _nvIEEE[Z_EXTADDR_LEN];
#pragma required=_nvIEEE
#endif

#pragma location="RESERVED_ADDRESS_SPACE"
__no_init uint8 _reserved[1932];
#pragma required=_reserved
#endif

// 64-bit Extended Address of this device
uint8 aExtendedAddress[8];

// Registered keys task ID, initialized to NOT USED.
static uint8 registeredKeysTaskID = NO_TASK_ID;

static void ChkReset( void );

void InitBoard( uint8 level )
{
  if ( level == OB_COLD )
  {
    // IAR does not zero-out this byte below the XSTACK.
    *(uint8 *)0x0 = 0;
    // Interrupts off
    osal_int_disable( INTS_ALL );
    // Check for Brown-Out reset
    ChkReset();
  }
  else  // !OB_COLD
  {
    /* Initialize Key stuff */
    HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);
  }
}

void ChkReset( void )
{
  uint8 rib;

  // Isolate reset indicator bits
  rib = SLEEPSTA & LRESET;

  if ( rib == RESETPO )
  {
    // Put code here to handle Power-On reset
  }
  else if ( rib == RESETEX )
  {
    // Put code here to handle External reset
  }
  else if ( rib == RESETWD )
  {
    // Put code here to handle WatchDog reset
  }
  else  // Unknown reason - not expected.
  {
    HAL_ASSERT(0);
  }
}

uint8 RegisterForKeys( uint8 task_id )
{
  // Allow only the first task
  if ( registeredKeysTaskID == NO_TASK_ID )
  {
    registeredKeysTaskID = task_id;
    return ( true );
  }
  else
    return ( false );
}

uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
{
  keyChange_t *msgPtr;

  if ( registeredKeysTaskID != NO_TASK_ID )
  {
    // Send the address to the task
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }
  else
    return ( ZFailure );
}

void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
  uint8 shift;
  (void)state;

  shift = (keys & HAL_KEY_SW_6) ? true : false;

  if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
  {
    // Process SW1 here
    if ( keys & HAL_KEY_SW_1 )  // Switch 1
    {
    }
    // Process SW2 here
    if ( keys & HAL_KEY_SW_2 )  // Switch 2
    {
    }
    // Process SW3 here
    if ( keys & HAL_KEY_SW_3 )  // Switch 3
    {
    }
    // Process SW4 here
    if ( keys & HAL_KEY_SW_4 )  // Switch 4
    {
    }
    // Process SW5 here
    if ( keys & HAL_KEY_SW_5 )  // Switch 5
    {
    }
    // Process SW6 here
    if ( keys & HAL_KEY_SW_6 )  // Switch 6
    {
    }
  }
}

uint16 OnBoard_stack_used(void)
{
  uint8 const *ptr;
  uint8 cnt = 0;

  for (ptr = CSTACK_END; ptr > CSTACK_BEG; ptr--)
  {
    if (STACK_INIT_VALUE == *ptr)
    {
      if (++cnt >= MIN_RAM_INIT)
      {
        ptr += MIN_RAM_INIT;
        break;
      }
    }
    else
    {
      cnt = 0;
    }
  }

  return (uint16)(CSTACK_END - ptr + 1);
}

void _itoa(uint16 num, uint8 *buf, uint8 radix)
{
  char c,i;
  uint8 *p, rst[5];

  p = rst;
  for ( i=0; i<5; i++,p++ )
  {
    c = num % radix;  // Isolate a digit
    *p = c + (( c < 10 ) ? '0' : '7');  // Convert to Ascii
    num /= radix;
    if ( !num )
      break;
  }

  for ( c=0 ; c<=i; c++ )
    *buf++ = *p--;  // Reverse character order

  *buf = '\0';
}

uint16 Onboard_rand( void )
{
  return ( MAC_RADIO_RANDOM_WORD() );
}

void Onboard_wait( uint16 timeout )
{
  while (timeout--)
  {
    asm("NOP");
    asm("NOP");
    asm("NOP");
  }
}

__near_func void Onboard_soft_reset( void )
{
  HAL_DISABLE_INTERRUPTS();
  // Abort all DMA channels to insure that ongoing operations do not
  // interfere with re-configuration.
  DMAARM = 0x80 | 0x1F;
  asm("LJMP 0x0");
}


void BigLight_On( void )
{
  // Put code here to turn on an external light
}

void BigLight_Off( void )
{
  // Put code here to turn off an external light
}

void BuzzerControl( uint8 on )
{
  // Put code here to turn a buzzer on/off
  (void)on;
}

void Dimmer( uint8 lvl )
{
  // Put code here to control a dimmer
  (void)lvl;
}

// No dip switches on this board
uint8 GetUserDipSw( void )
{
  return 0;
}

OnBoard.h

#ifndef ONBOARD_H
#define ONBOARD_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "hal_mcu.h"
#include "hal_uart.h"
#include "hal_sleep.h"
#include "osal.h"

// 64-bit Extended Address of this device
extern uint8 aExtendedAddress[8];

// Timer clock and power-saving definitions
#define TIMER_DECR_TIME    1  // 1ms - has to be matched with TC_OCC

/* OSAL timer defines */
#define TICK_TIME   1000   // Timer per tick - in micro-sec

#define TICK_COUNT  1  // 32 Mhz Output Compare Count

/* CC2430 DEFINITIONS */

// MEMCTR bit definitions
#define ALWAYS1    0x01  // Reserved: always=1
#define CACHDIS    0x02  // Flash cache: disable=1
#define FMAP0      0x10  // Flash bank map, bit0
#define FMAP1      0x20  // Flash bank map, bit1
#define FMAP       0x30  // Flash bank map, mask
#define MUNIF      0x40  // Memory mapping: unified=1

// PCON bit definitions
#define PMODESET   0x01  // Power mode control: 1=set PMx

// Reset bit definitions
#define LRESET     0x18  // Last reset bit mask
#define RESETPO    0x00  // Power-On reset
#define RESETEX    0x08  // External reset
#define RESETWD    0x10  // WatchDog reset

/* GPIO PORT DEFINITIONS */
// GPIO bit definitions
#define GPIO_0     0x01  // Px_0: GPIO=0, PIO=1
#define GPIO_1     0x02  // Px_1: GPIO=0, PIO=1
#define GPIO_2     0x04  // Px_2: GPIO=0, PIO=1
#define GPIO_3     0x08  // Px_3: GPIO=0, PIO=1
#define GPIO_4     0x10  // Px_4: GPIO=0, PIO=1
#define GPIO_5     0x20  // Px_5: GPIO=0, PIO=1
#define GPIO_6     0x40  // Px_6: GPIO=0, PIO=1
#define GPIO_7     0x80  // Px_7: GPIO=0, PIO=1

/* WATCHDOG TIMER DEFINITIONS */
// WDCTL bit definitions

#define WDINT0     0x01  // Interval, bit0
#define WDINT1     0x02  // Interval, bit1
#define WDINT      0x03  // Interval, mask
#define WDMODE     0x04  // Mode: watchdog=0, timer=1
#define WDEN       0x08  // Timer: disabled=0, enabled=1
#define WDCLR0     0x10  // Clear timer, bit0
#define WDCLR1     0x20  // Clear timer, bit1
#define WDCLR2     0x40  // Clear timer, bit2
#define WDCLR3     0x80  // Clear timer, bit3
#define WDCLR      0xF0  // Clear timer, mask

// WD timer intervals
#define WDTISH     0x03  // Short: clk * 64
#define WDTIMD     0x02  // Medium: clk * 512
#define WDTILG     0x01  // Long: clk * 8192
#define WDTIMX     0x00  // Maximum: clk * 32768

// WD clear timer patterns
#define WDCLP1     0xA0  // Clear pattern 1
#define WDCLP2     0x50  // Clear pattern 2


// These Key definitions are unique to this development system.
// They are used to bypass functions when starting up the device.
#define SW_BYPASS_NV    HAL_KEY_SW_5  // Bypass Network layer NV restore
#define SW_BYPASS_START HAL_KEY_SW_1  // Bypass Network initialization

// LCD Support Defintions
#ifdef LCD_SUPPORTED
  #if !defined DEBUG
    #define DEBUG  0
  #endif
  #if LCD_SUPPORTED==DEBUG
    #define SERIAL_DEBUG_SUPPORTED  // Serial-debug
  #endif
#else // No LCD support
  #undef SERIAL_DEBUG_SUPPORTED  // No serial-debug
#endif

/* Serial Port Definitions */
#if defined (ZAPP_P1)
  #define ZAPP_PORT HAL_UART_PORT_0
#elif defined (ZAPP_P2)
  #define ZAPP_PORT HAL_UART_PORT_1
#else
  #undef ZAPP_PORT
#endif
#if defined (ZTOOL_P1)
  #define ZTOOL_PORT HAL_UART_PORT_0
#elif defined (ZTOOL_P2)
  #define ZTOOL_PORT HAL_UART_PORT_1
#else
  #undef ZTOOL_PORT
#endif

#define MT_UART_TX_BUFF_MAX  128
#define MT_UART_RX_BUFF_MAX  128
#define MT_UART_THRESHOLD   (MT_UART_RX_BUFF_MAX / 2)
#define MT_UART_IDLE_TIMEOUT 6

// Restart system from absolute beginning
// Disables interrupts, forces WatchDog reset
#define SystemReset()       \
{                           \
  HAL_DISABLE_INTERRUPTS(); \
  HAL_SYSTEM_RESET();       \
}

#define SystemResetSoft()  Onboard_soft_reset()

/* Reset reason for reset indication */
#define ResetReason() ((SLEEPSTA >> 3) & 0x03)

/* WATCHDOG TIMER DEFINITIONS */
#define WatchDogEnable(wdti)              \
{                                         \
  WDCTL = WDCLP1 | WDEN | (wdti & WDINT); \
  WDCTL = WDCLP2 | WDEN | (wdti & WDINT); \
}

// Wait for specified microseconds
#define MicroWait(t) Onboard_wait(t)

#define OSAL_SET_CPU_INTO_SLEEP(timeout) halSleep(timeout); /* Called from OSAL_PwrMgr */

#ifdef __IAR_SYSTEMS_ICC__
// Internal (MCU) Stack addresses
#define CSTACK_BEG ((uint8 const *)(_Pragma("segment=\"XSTACK\"") __segment_begin("XSTACK")))
#define CSTACK_END ((uint8 const *)(_Pragma("segment=\"XSTACK\"") __segment_end("XSTACK"))-1)
// Stack Initialization Value
#define STACK_INIT_VALUE  0xCD
#else
#error Check compiler compatibility.
#endif

/* The following Heap sizes are setup for typical TI sample applications,
 * and should be adjusted to your systems requirements.
 */
#if !defined INT_HEAP_LEN
#if defined RTR_NWK
  #define INT_HEAP_LEN  3072
#else
  #define INT_HEAP_LEN  2048
#endif
#endif
#define MAXMEMHEAP INT_HEAP_LEN

#define KEY_CHANGE_SHIFT_IDX 1
#define KEY_CHANGE_KEYS_IDX  2

// Initialization levels
#define OB_COLD  0
#define OB_WARM  1
#define OB_READY 2

#ifdef LCD_SUPPORTED
  #define BUZZER_OFF  0
  #define BUZZER_ON   1
  #define BUZZER_BLIP 2
#endif

typedef struct
{
  osal_event_hdr_t hdr;
  uint8 state; // shift
  uint8 keys;  // keys
} keyChange_t;

  extern void InitBoard( uint8 level );

  extern uint32 TimerElapsed( void );

  extern uint8 RegisterForKeys( uint8 task_id );

  extern uint8 OnBoard_SendKeys( uint8 keys, uint8 shift );

  extern void _itoa( uint16 num, uint8 *buf, uint8 radix );


  extern void Dimmer( uint8 lvl );

  extern void BigLight_On( void );

  extern void BigLight_Off( void );

  extern void BuzzerControl( uint8 on );

  extern uint8 GetUserDipSw( void );

  extern uint16 OnBoard_stack_used( void );

  extern void OnBoard_KeyCallback ( uint8 keys, uint8 state );

  extern uint16 Onboard_rand( void );

  extern void Onboard_wait( uint16 timeout );

  extern __near_func void Onboard_soft_reset( void );


#ifdef __cplusplus
}
#endif

#endif // ONBOARD_H

ZMain.c

#ifndef NONWK
#include "AF.h"
#endif
#include "hal_adc.h"
#include "hal_flash.h"
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_drivers.h"
#include "OnBoard.h"
#include "OSAL.h"
#include "OSAL_Nv.h"
#include "ZComDef.h"
#include "ZMAC.h" 

static void zmain_ext_addr( void );
#if defined ZCL_KEY_ESTABLISH
static void zmain_cert_init( void );
#endif
static void zmain_dev_info( void );
static void zmain_vdd_check( void );

#ifdef LCD_SUPPORTED
static void zmain_lcd_init( void );
#endif

extern uint8 AppTitle[]; //应用程序名称

int main( void )
{
  // Turn off interrupts
  osal_int_disable( INTS_ALL );

  // Initialization for board related stuff such as LEDs
  HAL_BOARD_INIT();

  // Make sure supply voltage is high enough to run
  zmain_vdd_check();

  // Initialize board I/O
  InitBoard( OB_COLD );

  // Initialze HAL drivers
  HalDriverInit();

  // Initialize NV System
  osal_nv_init( NULL );

  // Initialize the MAC
  ZMacInit();

  // Determine the extended address
  zmain_ext_addr();

#if defined ZCL_KEY_ESTABLISH
  // Initialize the Certicom certificate information.
  zmain_cert_init();
#endif

  // Initialize basic NV items
  zgInit();

#ifndef NONWK
  // Since the AF isn't a task, call it's initialization routine
  afInit();
#endif

  // Initialize the operating system
  osal_init_system();

  // Allow interrupts
  osal_int_enable( INTS_ALL );

  // Final board initialization
  InitBoard( OB_READY );

  // Display information about this device
  zmain_dev_info();

  /* Display the device info on the LCD */
#ifdef LCD_SUPPORTED
  zmain_lcd_init();
#endif

#ifdef WDT_IN_PM1
  /* If WDT is used, this is a good place to enable it. */
  WatchDogEnable( WDTIMX );
#endif

  osal_start_system(); // No Return from here

  return 0;  // Shouldn't get here.
} // main()

static void zmain_vdd_check( void )
{
  uint8 cnt = 16;
  
  do {
    while (!HalAdcCheckVdd(VDD_MIN_RUN));
  } while (--cnt);
}

static void zmain_ext_addr(void)
{
  uint8 nullAddr[Z_EXTADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  uint8 writeNV = TRUE;

  // First check whether a non-erased extended address exists in the OSAL NV.
  if ((SUCCESS != osal_nv_item_init(ZCD_NV_EXTADDR, Z_EXTADDR_LEN, NULL))  ||
      (SUCCESS != osal_nv_read(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress)) ||
      (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN)))
  {
    // Attempt to read the extended address from the location on the lock bits page
    // where the programming tools know to reserve it.
    HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IEEE_OSET, aExtendedAddress, Z_EXTADDR_LEN);

    if (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN))
    {
      // Attempt to read the extended address from the designated location in the Info Page.
      if (!osal_memcmp((uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), nullAddr, Z_EXTADDR_LEN))
      {
        osal_memcpy(aExtendedAddress, (uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), Z_EXTADDR_LEN);
      }
      else  // No valid extended address was found.
      {
        uint8 idx;
        
#if !defined ( NV_RESTORE )
        writeNV = FALSE;  // Make this a temporary IEEE address
#endif

        /* Attempt to create a sufficiently random extended address for expediency.
         * Note: this is only valid/legal in a test environment and
         *       must never be used for a commercial product.
         */
        for (idx = 0; idx < (Z_EXTADDR_LEN - 2);)
        {
          uint16 randy = osal_rand();
          aExtendedAddress[idx++] = LO_UINT16(randy);
          aExtendedAddress[idx++] = HI_UINT16(randy);
        }
        // Next-to-MSB identifies ZigBee devicetype.
#if ZG_BUILD_COORDINATOR_TYPE && !ZG_BUILD_JOINING_TYPE
        aExtendedAddress[idx++] = 0x10;
#elif ZG_BUILD_RTRONLY_TYPE
        aExtendedAddress[idx++] = 0x20;
#else
        aExtendedAddress[idx++] = 0x30;
#endif
        // MSB has historical signficance.
        aExtendedAddress[idx] = 0xF8;
      }
    }

    if (writeNV)
    {
      (void)osal_nv_write(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress);
    }
  }

  // Set the MAC PIB extended address according to results from above.
  (void)ZMacSetReq(MAC_EXTENDED_ADDRESS, aExtendedAddress);
}

#if defined ZCL_KEY_ESTABLISH

static void zmain_cert_init(void)
{
  uint8 certData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN];
  uint8 nullData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN] = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  };

  (void)osal_nv_item_init(ZCD_NV_IMPLICIT_CERTIFICATE, ZCL_KE_IMPLICIT_CERTIFICATE_LEN, NULL);
  (void)osal_nv_item_init(ZCD_NV_DEVICE_PRIVATE_KEY, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, NULL);

  // First check whether non-null certificate data exists in the OSAL NV. To save on code space,
  // just use the ZCD_NV_CA_PUBLIC_KEY as the bellwether for all three.
  if ((SUCCESS != osal_nv_item_init(ZCD_NV_CA_PUBLIC_KEY, ZCL_KE_CA_PUBLIC_KEY_LEN, NULL))    ||
      (SUCCESS != osal_nv_read(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData))  ||
      (osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN)))
  {
    // Attempt to read the certificate data from its corresponding location on the lock bits page.
    HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_CA_PUBLIC_KEY_OSET, certData,
                                         ZCL_KE_CA_PUBLIC_KEY_LEN);
    // If the certificate data is not NULL, use it to update the corresponding NV items.
    if (!osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN))
    {
      (void)osal_nv_write(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData);
      HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IMPLICIT_CERT_OSET, certData,
                                           ZCL_KE_IMPLICIT_CERTIFICATE_LEN);
      (void)osal_nv_write(ZCD_NV_IMPLICIT_CERTIFICATE, 0,
                          ZCL_KE_IMPLICIT_CERTIFICATE_LEN, certData);
      HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_DEV_PRIVATE_KEY_OSET, certData,
                                        ZCL_KE_DEVICE_PRIVATE_KEY_LEN);
      (void)osal_nv_write(ZCD_NV_DEVICE_PRIVATE_KEY, 0, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, certData);
    }
  }
}
#endif

static void zmain_dev_info(void)
{
#ifdef LCD_SUPPORTED
  uint8 i;
  uint8 *xad;
  uint8 lcd_buf[Z_EXTADDR_LEN*2+1];

  // Display the extended address.
  xad = aExtendedAddress + Z_EXTADDR_LEN - 1;

  for (i = 0; i < Z_EXTADDR_LEN*2; xad--)
  {
    uint8 ch;
    ch = (*xad >> 4) & 0x0F;
    lcd_buf[i++] = ch + (( ch < 10 ) ? '0' : '7');
    ch = *xad & 0x0F;
    lcd_buf[i++] = ch + (( ch < 10 ) ? '0' : '7');
  }
  lcd_buf[Z_EXTADDR_LEN*2] = '\0';
  
  //DrawRectFill(0 ,0 ,128,128,GREEN);//背景色
  DrawRectFill(3 ,20 ,122,106,WHITE); //显示窗口
   
  Color    = BLACK; //前景色
  Color_BK = GREEN; //背景色
  LCD_write_EN_string(64-7*osal_strlen((char *)AppTitle)/2,3,AppTitle); //显示标题
  
  Color    = BLACK; //前景色
  Color_BK = WHITE; //背景色
  HalLcdWriteString( "IEEE: ", HAL_LCD_LINE_3 );
  Color    = BLUE;                    
  HalLcdWriteString( (char*)lcd_buf, HAL_LCD_LINE_4 );
  
  Color    = RED; 
  LCD_write_CN_string(9, 95, "不吃橘子的橘猫");
#endif
}

#ifdef LCD_SUPPORTED

static void zmain_lcd_init ( void )
{
#ifdef SERIAL_DEBUG_SUPPORTED
  {
    HalLcdWriteString( "TexasInstruments", HAL_LCD_LINE_1 );

#if defined( MT_MAC_FUNC )
#if defined( ZDO_COORDINATOR )
      HalLcdWriteString( "MAC-MT Coord", HAL_LCD_LINE_2 );
#else
      HalLcdWriteString( "MAC-MT Device", HAL_LCD_LINE_2 );
#endif // ZDO
#elif defined( MT_NWK_FUNC )
#if defined( ZDO_COORDINATOR )
      HalLcdWriteString( "NWK Coordinator", HAL_LCD_LINE_2 );
#else
      HalLcdWriteString( "NWK Device", HAL_LCD_LINE_2 );
#endif // ZDO
#endif // MT_FUNC
  }
#endif // SERIAL_DEBUG_SUPPORTED
}
#endif

Output(输出文件)

f8wRoSampleApp.d51

f8wRoSampleApp.map

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃橘子的橘猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值