Skip to content

Clear End Device Initiator when relaying an end device child's frame - #66

Merged
puddly merged 1 commit into
zigpy:devfrom
zigpy-review-bot:zigpy-bot/clear-end-device-initiator-on-relay
Oct 16, 2026
Merged

puddly merged 1 commit into
zigpy:devfrom
zigpy-review-bot:zigpy-bot/clear-end-device-initiator-on-relay

Conversation

@zigpy-review-bot

Copy link
Copy Markdown
Contributor

Summary

When ziggurat relays a frame sent by one of its end device children, it keeps the End Device Initiator bit of the NWK frame control set. Zigbee R23.2 §3.3.1.1.8 requires the router parent to clear that bit when relaying such a frame, and §3.6.2.2 has every other router drop a frame carrying the bit unless its source is an end device in that router's own neighbor table. So a group command an end device remote (an IKEA TRADFRI remote, for example) broadcasts through a ziggurat parent goes out with frame control 0x2248, and the routers that receive the relayed copy, the bound bulbs included, drop it.

Fixes #65. The analysis is ChristophKaser's: the issue identifies the missing clear, the relay paths, and the spec sections, and the reporter confirmed that clearing the bit before forwarding makes the bound bulb respond.

Changes

  • Neighbors::clear_end_device_initiator_for_relay (ziggurat-zigbee) clears the bit only when the frame's NWK source is an end device child in our neighbor table, which is the source validation §3.3.1.1.8 asks for. Frames from any other source keep the bit unchanged.
  • maybe_relay_broadcast applies it to the relayed copy before anything is queued. The over-the-air relay, its passive-ack retransmits, and the copies fanned out to sleepy children through the indirect queue all go out with the bit cleared. The fan-out was previously built from the unmodified inbound frame, and an end device drops any frame with the bit set (§3.6.2.2, step 1).
  • relay_unicast_nwk_frame applies it after the radius check, so the sender's retries and the indirect queue for a sleepy destination carry the cleared bit as well.
  • Frames ziggurat originates are unaffected; they are always built with the bit clear.

Testing

  • New unit tests in ziggurat-zigbee/src/nwk/neighbors.rs: frame control 0x2248 from an end device child serializes as 0x0248 after the clear, and the bit is left alone for an unknown source, a router child, and a frame without the bit.
  • cargo test -p ziggurat-zigbee (28 passed), cargo test -p ziggurat-driver (builds, the crate has no tests), and cargo clippy -p ziggurat-zigbee -p ziggurat-driver --all-targets --all-features -- -D warnings -Dclippy::all -Dclippy::nursery are clean. cargo fmt --all --check is clean.
  • Not tested on hardware by the bot. The reporter's equivalent local change was tested against 392d4c7, which is this branch's base.

Open items

  • Ziggurat does not enforce the receive side of §3.6.2.2: it does not drop a frame whose End Device Initiator bit is set when the source is not one of its end device children, and it does not send the Leave with Rejoin that the spec asks for in that case. This PR leaves that out because it is a behaviour change of its own.

Zigbee R23.2 3.3.1.1.8: after validating the source, a router parent SHALL
clear the End Device Initiator bit when relaying a message sent by one of its
end device children. Ziggurat relayed these frames with the bit still set, so
other routers, which find no end device with that source in their own neighbor
table, drop them (3.6.2.2). A group command an end device remote broadcasts
through its ziggurat parent was therefore dropped by the routers that received
the relayed copy, the bound bulbs included.

Clear the bit for frames whose NWK source is one of our end device children in
both relay paths: the broadcast relay (the over-the-air copy, its retransmits,
and the indirect copies fanned out to sleepy children) and the unicast relay
(sender retries and the indirect queue).
@zigpy-review-bot zigpy-review-bot added the bugfix This PR fixes a bug label Oct 14, 2026
@puddly
puddly merged commit 913a5c2 into zigpy:dev Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix This PR fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

End Device Initiator flag remains set when forwarding remote group commands

2 participants