ZigBee 终端设备离线后脱离网络

z-stack,zigbee 2022-08-07 3498 次浏览 次点赞


理清思路

这里记录之前的一次异常处理,直接现象是多功能传感器(ZigBee End-Device,以下简称ZED)通过小米86盒开关 路由设备(ZigBee Router,以下简称ZR)关联加入网络很容易脱离网络。

首先,需要理清的ZED在IEEE-802.15.4 规定为RFD (精简功能设备),精剪功能主要在不能中继数据,作为树状网络拓扑的终端存在,同时受限于功耗,通常会选择大部分时间休眠以节约功耗。为了保证设备休眠能够正常接收数据,所以接收数据的时候选择间接交易,也就是父节点不直接向终端设备发送数据,是唤醒后的终端设备主动去轮询父节点字节是否有数据需要接收。所以其必须依赖父节点完成正常的通信业务,

通常地,如果ZED多次才能够父亲轮询数据失败,机会考虑其成为孤儿并且考虑重新加入网络,基于此特性在TI 协议栈被 描述为可移动设备(Portable Devices)。

  • Z-Stack Developer’s Guide->7.Portable Devices
  • ZigBee Specification 2012 ->2.Application Layer Specification->2.4.3.3.7 Mgmt_Permit_Joining_req
  • Z-Stack Developer’s Guide->10. Security (Page 34)
  • ZigBee Specification 2012 ->4.Security Services Specification->4.6 Functional Description

不允许加入

下面是同父节点失去联系的ZED重新重新加入网络的流程,不幸的是,没有成功加入网络,还直接被踢出了网络。

  1. 我成为孤儿了;
  2. 小米插座:让我作为你的父亲吧,给你取个新的名字;
  3. 我有新名字了;
  4. 小米插座:这事我还得通信下信任中心(Trust Center)登记下,让他给你一个通信密钥;
  5. 信任中心:这事我不同意,现阶段我们不允许任何人加入,@小米插座 剔除了他;
  6. 好的,离开网络;

设备离线,发起了rejoin,通过关联小米路由加入网络,小米路由发起请求密钥(update device)并且通过如下的Status 标记为Unsecured Rejoin

成功收到如上update device 命令后,ZStack根据实际的Status 选择不同的处理,如果是Secure join ,理论上不会任何操作。

//ZDSecmgr.c  Function.ZDSecMgrUpdateDeviceInd  Line.1754
void ZDSecMgrUpdateDeviceInd( ZDO_UpdateDeviceInd_t* ind  {
  ZDSecMgrDevice_t device;
  // Trust Center should identify the type of JOIN/REJOIN and
  // Transport the NWK key accordingly, it will only be transported for:
  //              APSME_UD_STANDARD_UNSECURED_JOIN
  //   OR         APSME_UD_STANDARD_TRUST_CENTER_REJOIN
  if ( ind->status != APSME_UD_DEVICE_LEFT )  {
    if ( ind->status == APSME_UD_STANDARD_SECURED_REJOIN) {
      device.secure = TRUE;
    }
    ZDSecMgrDeviceJoin( &device );
  }
}

但是状态如果是Unsecure join 这里会直接交由信任中心(Trust Center) 处理。信任中心会根据ZDSecMgrDeviceValidate 的结果来决定添加设备(ZDSecMgrAddrStore)并且交换传输密钥 (ZDSecMgrSendNwkKey)还是直接踢出设备(ZDSecMgrDeviceRemove)。

//ZDSecmgr.c  Function.ZDSecMgrDeviceJoin  Line.1112
ZStatus_t ZDSecMgrDeviceJoin( ZDSecMgrDevice_t* device ) {
  ZStatus_t status = ZSuccess;
  uint16    ami;

  // attempt to validate device that joined/rejoined without security
  if ( device->secure == FALSE )  {
    status = ZDSecMgrDeviceValidate( device );
  }

  if ( status == ZSuccess ) {
    // 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 );
    }
  }
  if ( status != ZSuccess ) {
    // not allowed or transport key failed, remove the device
    ZDSecMgrDeviceRemove( device );
  }

ZDSecMgrDeviceValidate 是通过ZDSecMgrPermitJoiningEnabledzgSecurePermitJoin,使能位决定的。

//ZDSecMgr.c Function.ZDSecMgrDeviceValidate Line.1087
ZStatus_t ZDSecMgrDeviceValidate( ZDSecMgrDevice_t* device ) {
  ZStatus_t status;

  if ( ZDSecMgrPermitJoiningEnabled == TRUE ) {
      // For test purpose, turning off the zgSecurePermitJoin flag will force
      // the trust center to reject any newly joining devices by sending
      // Remove-device to the parents.
      if ( zgSecurePermitJoin == FALSE )  {
        status = ZNwkUnknownDevice;
      }
  } else {
    status = ZNwkUnknownDevice;
  }
  return status;
}

而控制如上ZDSecMgrPermitJoiningEnabledzgSecurePermitJoin 正是我们的Web界面控制的允许入网。

//zcl_samplesw Function.PermitJoin  Line885  
NLME_PermitJoiningRequest(60);
ZDP_MgmtPermitJoinReq( &MXJ_GbAddr, 60, TRUE, TRUE);

PermitJoin是如何控制TC的工作状态

//zcl_samplesw Function.PermitJoin  Line885  
NLME_PermitJoiningRequest(60);
ZDP_MgmtPermitJoinReq( &MXJ_GbAddr, 60, TRUE, TRUE);

先说结论,如上的Web页面控制的允许入网 功能对应的代码其实是控制了三个功能;

  • 协调器的Mac层允许关联加入NLME_PermitJoiningRequest

  • 广播允许加入命令,同步该允许使能到每一个路由 ZDP_MgmtPermitJoinReq

  • 控制信任中心的使能标志;

    该使能标志通过ZDP_MgmtPermitJoinReq 通过其第三个使能参数决定的。

    TcSignificance –  This is a boolean value. If it is set to 0x01 and the remote device is the trust center, the command 
    affects the trust center authentication policy as described in ZigBee Specification Section 2.4.3.3.7.2.  

对于第三点,是如何影响到信任中心(Trust Center)功能使能的。需要继续review代码。

//ZDSecMgr.c Function.ZDSecMgrDeviceValidate Line.1803
void ZDO_ProcessMgmtPermitJoinReq( zdoIncomingMsg_t *inMsg ) {
  if ( tcsig == TRUE ) {
      ZDSecMgrPermitJoining( duration );
  }

上面代码显示在收到PermitJoin 后的信任中心选择通过tcsig标志位来处理是否禁止/使能 信任中心的功能。

也就是ZDP_MgmtPermitJoinReq 第三个形参,我们设置为FALSE 即表示通过permit join 命令不控制TC功能。

ZDP_MgmtPermitJoinReq( &MXJ_GbAddr, 60, FALSE, TRUE);

允许加入

如下是为设置信任中心允许设备加入后的抓包,ZR成功加入到网络。

  1. 我成为孤儿了;
  2. 小米插座:让我作为你的父亲吧,给你取个新的名字;
  3. 我有新名字了;
  4. 小米插座:这事我还得通信下信任中心(Trust Center)让他给你一个通信密钥;
  5. 信任中心:允许加入,给你密钥;
  6. 正常通信了;


本文由 Jay 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处,点赞1

还不快抢沙发

添加新评论