silabs黑名单机制
在BC协议当中,在主节点有白名单机制,白名单就是主节点允许加入该网络的子节点的档案/地址。如果一个子节点加入该网络,但是主节点没有该子节点的档案或者地址时,在子节点入网后,子节点会主动上报给特定的族ID一个数据包,这个数据包有子节点的档案或者地址。主节点的这个特定的族ID收到这个数据后会进行解释这个数据包,并把档案存蓄起来,然后拿这个档案去和自己的白名单进行对比,如果有该档案存在,则允许该节点在网络工作,如果没有该档案存在,则主节点会发送一个退网数据包给该节点对应的族ID,该节点对应的族ID收到这个数据包的时候,解析判断是否为退网命令,如果是,则调用退网函数或者延迟一会再调用退网命令。子节点在退网之前会调用相关的函数获取这个主节点的网络信息,如频道、PANID等信息,并且把这个信道上的对应PANID屏蔽起来。屏蔽就是自定义一个数组,每次扫到网络的时候会进行查询看看这个网络的信道对应的PANID是否已经在该数组里面,如果在,直接return结束该函数。(退网屏蔽)
在这里密码错误时也会进行屏蔽网络处理。子节点在扫描网络的过程中准备加入网络时发生了密钥错误,此时可以在密钥错误下获取这个网络的信道以及PANID等信息,并把该信道上的这个PANID存放在屏蔽的数组里去,在下次准备加入网络时会进行遍历这个屏蔽的数组,如果遍历该数组有该网络的存在,则直接return结束当前函数。(密钥错误屏蔽)。
如果你的子节点已经安装在现场,而在这个环境中有多个主节点,这些主节点因为认为或者是其他原因导致网络的信道或者PANID变化,并且有些网络先前可能是没有该子节点的档案,后期再加入档案的,这种情况下很可能到导致子节点已经把该网络已经屏蔽处理了,对于这个问题是这样处理的。1.在子节点代码里可以进行判断,如果没有网络的情况下,间隔十分钟左右清除该屏蔽数组上所有的网络。这样就可以避免这个问题了,因为不清除的话是永远屏蔽的,除非你想办法让该子节点复位或者关掉再开,这样就比较麻烦了,因此,在做黑名单机制时,在没有网络的情况下是很有必要进行间隔时间的清除。
具体代码实现:
黑名单屏蔽网络代码实现例子:
定义:
#define EACH_CHANNEL_MASK_NUM 20//每个信道可以屏蔽20个PANID
#define BC_MASK_PANID_NUM EACH_CHANNEL_MASK_NUM*16 /*EACH_CHANNEL_MASK_NUM:每个信道屏蔽PANID的个数;16:为16个信道*/
int16u bcMaskPanId[BC_MASK_PANID_NUM] = {0xFFFF};//屏蔽网络的数组
int16u bcPreKeyMaskPanId = 0xFFFF; //每次准备要加入网络时都会把PANID赋值给该变量
//外部声明
extern int16u bcMaskPanId[BC_MASK_PANID_NUM];//放到公共的头文件以便使用
//初始化,初始化时再次确保屏蔽数组全部都是空的
for(i=0;i<BC_MASK_PANID_NUM;i++) //BC_MASK_PANID_NUM=20*16
{
bcMaskPanId[i]=0xFFFF;
}
//不管是退网屏蔽处理还是密钥错误屏蔽处理都是在这个函数里面处理
//“void emberStackStatusHandler(EmberStatus status)”
//退网屏蔽处理:
//case MSG_SINK_BroadcastLeaveNet:
//子节点在对应的族ID下收到退网命令时要进行这里的处理屏蔽网络
//channelTemp:获取当前的信道;for:就是在找一个空的位置存储发这个退网命令的PANID
//channelTemp*EACH_CHANNEL_MASK_NUM+i:每个信道往上加。
channelTemp = emberGetRadioChannel()-11;
emberSerialPrintf(APP_SERIAL, "; channelTemp=%d\r\n",channelTemp);
for(i=0;i<EACH_CHANNEL_MASK_NUM;i++){
if(bcMaskPanId[channelTemp*EACH_CHANNEL_MASK_NUM+i] == 0xFFFF){
bcMaskPanId[channelTemp*EACH_CHANNEL_MASK_NUM+i]= emberGetPanId();
break;
}
}
//密钥错误屏蔽处理:
//case EMBER_PRECONFIGURED_KEY_REQUIRED:
#define APP_EXTENDED_PANID {0,0,0,0,0,0,0,0}
int8u extendedPanId[EXTENDED_PAN_ID_SIZE] = APP_EXTENDED_PANID;
channelTemp = emberGetRadioChannel()-11;
for(i=0;i<EACH_CHANNEL_MASK_NUM;i++){
if(bcMaskPanId[channelTemp*EACH_CHANNEL_MASK_NUM+i] == 0xFFFF){
bcMaskPanId[channelTemp*EACH_CHANNEL_MASK_NUM+i] = bcPreKeyMaskPanId;
break;
}
}
//密钥错误时继续扫描
//tempChannelMask:这个就是扫描的信道,转为二进制时16个位,1代表要扫描,0则不扫描
tempChannelMask= (0xfffffffeUL<<emberGetRadioChannel())&EMBER_ALL_802_15_4_CHANNELS_MASK;
emberSerialPrintf(APP_SERIAL,"tempChannelMask:0x%4x\r\n",tempChannelMask);
emberScanForJoinableNetwork(tempChannelMask,(int8u*) extendedPanId);
//在form-and-join.c
//不管是退网屏蔽还是密钥屏蔽都要在这个函数进行处理,也就是说在这个函数判断该网络//是否为屏蔽网络,如果是,则结束该网络。
// Helper functions
static void saveNetwork(EmberZigbeeNetwork *network, int8u lqi, int8s rssi)
{
int8u i;
NetworkInfo *finger;
int8u channelTemp; //add by hk 2013.04.28
// See if we already have that network.
for (i = 0; i < networkCount; i++) {
finger = formAndJoinGetNetworkPointer(i);
if (MEMCOMPARE(finger->network.extendedPanId,
network->extendedPanId,
EXTENDED_PAN_ID_SIZE) == 0) {
return;
}
}
if (formAndJoinSetBufferLength(networkCount + 1) != EMBER_SUCCESS) {
return;
}
// See if we already have that network.
channelTemp = network->channel-11;
for(i=0;i<EACH_CHANNEL_MASK_NUM;i++){
if(bcMaskPanId[channelTemp*EACH_CHANNEL_MASK_NUM+i] == network->panId){
SCAN_DEBUG_MSG("channelPanId[%d][", network->channel);
SCAN_DEBUG_MSG("%2x]", network->panId);
SCAN_DEBUG("is Masked\r\n");
return;
}
}
finger = formAndJoinGetNetworkPointer(networkCount);
networkCount += 1;
MEMMOVE(finger, network, sizeof(EmberZigbeeNetwork));
finger->lqi = lqi;
finger->rssi = rssi;
}
//密钥错误回调处理
void emberJoinableNetworkFoundHandler(EmberZigbeeNetwork *networkFound,
int8u lqi,
int8s rssi)
{
EmberNetworkParameters parameters;
int8u extendedPanId[EXTENDED_PAN_ID_SIZE] = {0,0,0,0,0,0,0,0};
MEMSET(¶meters, 0, sizeof(EmberNetworkParameters));
/* cut by lcg
MEMCOPY(parameters.extendedPanId,
networkFound->extendedPanId,
EXTENDED_PAN_ID_SIZE); */
MEMCOPY(parameters.extendedPanId, extendedPanId, EXTENDED_PAN_ID_SIZE);
parameters.panId = networkFound->panId;
bcPreKeyMaskPanId = networkFound->panId; //在这里进行赋值,密钥认证会调用该函数。
parameters.radioTxPower = APP_POWER;
parameters.radioChannel = networkFound->channel;
parameters.joinMethod = EMBER_USE_MAC_ASSOCIATION;
emberJoinNetwork(EMBER_ROUTER, ¶meters);
}
//清除屏蔽网络处理
//没有网络的情况下十分钟左右进行清理屏蔽数组处理(时间可以自己定义)
for(i=0;i<BC_MASK_PANID_NUM;i++){//16*20个全部清空
bcMaskPanId[i]=0xFFFF;
}