STM32WBA Zigbee® Rejoining

1. Introduction

Rejoining in Zigbee® allows a device that has already joined a network to rejoin the same network. There are several types of Rejoining mentioned in the Zigbee Specification.

Type of Rejoin Rejoin procedure Prerequisites Stack function call Example use case
Rejoin while joined to a network Secure Rejoin NWK key is present ZbStartupRejoin The device must establish a better parent
Rejoin while joined to a network but the NWK key is missing or outdated TC Rejoin TCLK is present ZbTrustCenterRejoin The device missed a NWK key update
Rejoin while not joined to a network TC Rejoin (suggested) or secure Rejoin TCLK is present or NWK key is present ZbStartup The device lost connection or left the network for a period of time
Rejoin while not joined and without security TC Rejoin Preconfigured TCLK is present (the TC must allow this type of Rejoin) ZbStartup The device lost both the NWK key and TCLK
NLME-LEAVE.request with rejoin==true Secure Rejoin (suggested) or TC Rejoin NWK key is present or TCLK is present ZbNlmeLeaveReq A device requests another device to leave and rejoin the network

2. How to trigger Rejoin

2.1. Rejoin while joined to a network

This is the more basic type of Rejoin. It has the fewest configurations and the fewest air transmissions. The device must already be connected to a network to call this function. The device can rejoin using the function call ZbStartupRejoin.

The prototype of the API is:

ZbStartupRejoin(struct ZigBeeT *zb, void (*callback)(struct ZbNlmeJoinConfT *conf, void *arg), void *cbarg)

2.2. Rejoin while joined to a network but the NWK key is missing or outdated

This type of Rejoin has one additional air transmission. It includes the transmission of a transport key command from TC to rejoining device, which contains the active NWK Key. The transport key command is encrypted at the APS layer using the TCLK. The transport key command is not encrypted at the NWK layer, as the receiving device does not yet have the active NWK key to decrypt. The device can rejoin using the function call ZbTrustCenterRejoin.

The prototype of the API is:

ZbTrustCenterRejoin(struct ZigBeeT *zb, void (*callback)(enum ZbStatusCodeT status, void *arg), void *cbarg)

2.3. Rejoin while not joined to a network

This type of Rejoin has several configurations. It requires setting parameter configPtr for the ZbStartup function.

In addition to the startup configurations, configPtr should be set as follows:

  • startupControl: ZbStartTypeRejoin
  • panId: 16-bit PAN ID of the network
  • extendedPanId: 64-bit extended PAN ID of the network

Then, depending on whether TC Rejoin or secure Rejoin is used:

Trust Center Rejoin (suggested)

  • security.trustCenterAddress: 64-bit IEEE address of the network TC

or secure Rejoin

  • security.networkKey: Byte-array containing the NWK key

The device can rejoin using the function call ZbStartup.

The prototype of the API is:

ZbStartup(struct ZigBeeT *zb, struct ZbStartupT *configPtr, void (*callback)(enum ZbStatusCodeT status, void *cb_arg), void *arg)

2.3.1. Additional information

2.3.1.1. Obtaining the 64-bit IEEE address of the network TC

The 64-bit IEEE address of the network TC can be obtained during a time when the rejoining device was connected to the network. That is:

uint64_t rejoinTcAddress;
ZbApsGet(stZigbeeAppInfo.pstZigbee, ZB_APS_IB_ID_TRUST_CENTER_ADDRESS, &rejoinTcAddress, sizeof(rejoinTcAddress));
2.3.1.2. Obtaining the byte-array containing the NWK key

The byte-array containing the NWK key can be obtained during a time when the rejoining device was connected to the network.

That is:

struct ZbNwkSecMaterialT rejoinNwkSecMaterial;
ZbNwkGet(stZigbeeAppInfo.pstZigbee, ZB_NWK_NIB_ID_SecurityMaterialSet, &rejoinNwkSecMaterial, sizeof(rejoinNwkSecMaterial));

The NWK key is found in the field rejoinNwkSecMaterial.key.

2.3.1.3. Obtaining and setting the TCLK for TC Rejoin

For a TC Rejoin, the TCLK must be set before function call ZbStartup in the APS layer using ZbApsSetIndex, if it does not persist. That is:

struct ZbApsmeKeyPairT rejoinKeyPair;
/* Set fields of rejoinKeyPair here, or copy the key from memory */
ZbApsSetIndex(stZigbeeAppInfo.pstZigbee, ZB_APS_IB_ID_DEVICE_KEY_PAIR_SET, &rejoinKeyPair, sizeof(rejoinKeyPair), 0);

The TCLK can be obtained during a time when the rejoining device was connected to the network. That is:

uint64_t rejoinTcAddress;
/* Set rejoinTcAddress here... */
struct ZbApsmeKeyPairT rejoinKeyPair;

unsigned int  i;
struct ZbApsmeKeyPairT keyPair;
for (i = 0;; i++)
{
  if (ZbApsGetIndex( stZigbeeAppInfo.pstZigbee, ZB_APS_IB_ID_DEVICE_KEY_PAIR_SET, keyPair, sizeof(*keyPair), i ) != ZB_NWK_STATUS_SUCCESS)
  {
    /* End of Key Pair Set */
    break;
  }

  if ( keyPair->deviceAddress == rejoinTcAddress )
  {
    memcpy(rejoinKeyPair, keyPair, sizeof(rejoinKeyPair))
  }
}

2.4. Rejoin while not joined and without security

This type of Rejoin requires minimal security. However, it can only be enabled by modifying the TC policy. Therefore, some changes must be made on the TC as well as the device.

The TC and device must disable TCLK exchange after joining.

uint8_t value = 0x00;
ZbBdbSet(stZigbeeAppInfo.pstZigbee, ZB_BDB_TrustCenterRequiresKeyExchange, &value, sizeof(value));

Additionally, the TC must modify its TC policy to allow Rejoin using the preconfigured TCLK.

uint32_t tcPolicy;
ZbApsGet(stZigbeeAppInfo.pstZigbee, ZB_APS_IB_ID_TRUST_CENTER_POLICY, &tcPolicy, sizeof(tcPolicy));
tcPolicy |= ZB_APSME_POLICY_ALLOW_REJOIN;
ZbApsSet(stZigbeeAppInfo.pstZigbee, ZB_APS_IB_ID_TRUST_CENTER_POLICY, &tcPolicy, sizeof(tcPolicy));

Then, parameter configPtr must be set for the ZbStartup function.

In addition to the startup configurations, configPtr should be set as follows:

  • startupControl: ZbStartTypeRejoin
  • panId: 16-bit PAN ID of the network
  • extendedPanId: 64-bit Extended PAN ID of the network

The device can rejoin using the function call ZbStartup.

The prototype of the API is:

ZbStartup(struct ZigBeeT *zb, struct ZbStartupT *configPtr, void (*callback)(enum ZbStatusCodeT status, void *cb_arg), void *arg)

2.4.1. Additional information

2.4.1.1. Rejoining a network without having joined in the past

Rejoining a network without having joined in the past is possible using this Rejoin procedure, contrary to the definition of rejoining.

The rejoining device only need to have the correct preconfigured TCLK (usually ZigbeeAlliance09 Key).

2.5. NLME-LEAVE.request with rejoin==true

This type of rejoin is used when one device is requesting another device (or itself) to leave the network and rejoin using the NLME-LEAVE.request. It requires setting parameter leaveReqPtr for the ZbNlmeLeaveReq function.

The device issuing the NLME-LEAVE.request should set leaveReqPtr as follows:

  • deviceAddr: 64-bit IEEE address of the device to leave and rejoin the network
  • rejoin: true
  • removeChildren: Remove the children of the device

The device can issue a NLME-LEAVE.request using the function call ZbNlmeLeaveReq.

The prototype of the API is:

ZbNlmeLeaveReq(struct ZigBeeT *zb, struct ZbNlmeLeaveReqT *leaveReqPtr, void (*callback)(struct ZbNlmeLeaveConfT *leaveConfPtr, void *arg), void *cbarg)

The device leaving and rejoining the network should be set to handle this message, using a message filter. It requires setting parameters mask, prio, and callback for the ZbMsgFilterRegister function.

mask and prio should be set as follows:

  • mask: ZB_MSG_FILTER_STACK_EVENT
  • prio: ZB_MSG_INTERNAL_PRIO + 1

callback should be set to a callback function resembling the following:

enum zb_msg_filter_rc callback(struct ZigBeeT *zb, uint32_t id, void *msg, void *cbarg)
{
  if (id == ZB_MSG_FILTER_STACK_EVENT) {
    struct ZbMsgStackEventT *event = msg;

    switch (event->type) {
      case ZB_MSG_STACK_EVENT_ATTEMPT_REJOIN:
        ZbStartupRejoin(zb, NULL, NULL); /* Could try other strategies here such as 3x Rejoin, then fallback on TC Rejoin if all fail */
        return ZB_MSG_DISCARD;
      default:
        break;
    }
  }

  return ZB_MSG_CONTINUE;
}

The device can register the message filter using the function call ZbMsgFilterRegister.

The prototype of the API is:

ZbMsgFilterRegister(struct ZigBeeT *zb, uint32_t mask, uint8_t prio, enum zb_msg_filter_rc (*callback)(struct ZigBeeT *zb, uint32_t id, void *msg, void *cbarg), void *arg);

3. Information on keys

3.1. Link key

A link key is a key shared between two devices, used to encrypt APS messages.

3.2. TCLK

A TCLK is a link key shared between a device and a Trust Center.

3.3. Preconfigured TCLK

A preconfigured TCLK is a TCLK that is known at boot. It is used prior to negotiating a new TCLK (unless TCLK negotiation is disabled at the TC). The most common preconfigured TCLK used is the ZigbeeAlliance09 Key.

3.4. NWK key

A NWK key is a key shared between all devices on a network, used to encrypt NWK messages.

4. Acronyms and definitions

Term Definition
APS Application support sublayer
NWK Network
TC Trust Center
TCLK Trust Center link key