Skip to content

esp: fix extended-address byte order for the hardware RX filter#84

Merged
ivmarkov merged 1 commit into
esp-rs:mainfrom
snabb:fix/esp-ext-addr-le
Jun 24, 2026
Merged

esp: fix extended-address byte order for the hardware RX filter#84
ivmarkov merged 1 commit into
esp-rs:mainfrom
snabb:fix/esp-ext-addr-le

Conversation

@snabb

@snabb snabb commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Problem

On ESP32 with esp-radio, OpenThread never attaches to a Thread network. The node transmits Parent Requests and receives multicast traffic fine, but receives zero unicast frames — so it never gets a Parent Response, and MLE attach times out. Because TX and multicast RX work, it looks like a higher-layer problem.

Root cause

An extended-address byte-order mismatch in the hardware RX address filter:

  • otPlatRadioSetExtendedAddress delivers the address in little-endian order (per openthread/platform/radio.h), and esp-radio programs its hardware filter with ext_addr.to_le_bytes() (fix: use little-endian byte order for IEEE 802.15.4 extended address esp-hal#5314, "use little-endian byte order for IEEE 802.15.4 extended address").
  • But the platform callback decoded it with from_be_bytes (and the MacRadio frame parser mirrored that), so Config.ext_addr / dst_ext_addr were byte-reversed vs the on-air little-endian address.

So the filter is loaded byte-reversed; the radio drops every unicast frame addressed to the node. (This was correct before esp-rs/esp-hal#5314, when esp-radio used big-endian; that change flipped esp-radio to the spec-correct little-endian and the decode side wasn't updated to match.)

Fix

Decode the extended address little-endian at the two sites that build the u64 from the byte slice — platform.rs (otPlatRadioSetExtendedAddress) and radio.rs (the MacRadio frame parser). This makes Config.ext_addr and the parsed dst_ext_addr match the on-air little-endian order and esp-radio's to_le_bytes hardware-filter programming.

Validation

esp32-c6, Matter over Thread: with the fix the device attaches to Thread and operates (commission, attribute reads, reboot auto-recovery); without it, attach never completes. (No nRF hardware here to exercise the MacRadio software-filter leg directly, but radio.rs is the matching counterpart so the two stay in agreement.)

🤖 Generated with Claude Code

@ivmarkov ivmarkov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for figuring out the root cause!

As discussed, instead of this change, please replace from_be_bytes with from_le_bytes at these two places (which are the buggy ones):

snabb added a commit to snabb/openthread that referenced this pull request Jun 24, 2026
…uning

For matter-embassy-esp32c6 on esp-radio 1.0.0-beta.0:

- platform.rs + radio.rs: decode the extended address little-endian
  (`from_le_bytes`). `otPlatRadioSetExtendedAddress` delivers it little-endian
  (openthread/platform/radio.h), but it was decoded big-endian, so on esp-radio
  (which programs its hw filter via `ext_addr.to_le_bytes()`, esp-rs/esp-hal#5314)
  the filter was byte-reversed -> all unicast RX dropped -> Thread never attached.
  (Matches the esp-rs#84 upstream fix.)
- esp.rs: rx_queue_size 50 -> 200 (proven value; absorbs fragmented
  commissioning/interview bursts, avoids "Receive queue full").
- builder.rs: NUM_MESSAGE_BUFFERS 128 -> 256; OT_LOG_LEVEL NOTE -> CRIT
  (a non-CRIT C side generates a log string per MLE/MAC event, starving the
  radio hot path during fragmented over-Thread commissioning).
- Cargo.toml: accept esp-radio 1.0.0-beta.0 (carries the AR-bit fix).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`otPlatRadioSetExtendedAddress` passes the extended address little-endian
(openthread/platform/radio.h), but it was decoded with `from_be_bytes` in the
platform callback, and the `MacRadio` frame parser mirrored that. So
`Config.ext_addr` and the parsed `dst_ext_addr` were byte-reversed vs the
on-air little-endian address. esp-radio programs its hardware filter via
`ext_addr.to_le_bytes()` (esp-rs/esp-hal#5314), so the filter never matched and
all unicast RX was dropped -> Thread never attached; the nRF `MacRadio` software
filter was off the same way. Decode little-endian at both sites.

Validated on esp32-c6 (Matter over Thread): with the fix the device attaches to
Thread and operates (commission, attribute reads, reboot auto-recovery); without
it, attach never completes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@snabb snabb force-pushed the fix/esp-ext-addr-le branch from d64be6d to f14d976 Compare June 24, 2026 06:24
@snabb

snabb commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Done — replaced from_be_bytes with from_le_bytes at both platform.rs (otPlatRadioSetExtendedAddress) and radio.rs (the MacRadio ext-addr parse), and reverted the esp.rs swap.

Re-tested on an esp32-c6 (Matter over Thread) with this exact from_le_bytes version: Thread attaches, the device operates (HA reads attributes), and it auto-recovers across reboots. The esp path is byte-identical to the swap I'd validated earlier; the radio.rs change keeps the nRF MacRadio software-filter parser consistent (no nRF hardware here to exercise that leg directly).

@ivmarkov ivmarkov merged commit 1ed1d7c into esp-rs:main Jun 24, 2026
6 checks passed
@snabb snabb deleted the fix/esp-ext-addr-le branch June 24, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants