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