Skip to content

fix: correct mesh packet construction, AES wire format, and node offl… - #13

Merged
retsimx merged 1 commit into
mainfrom
mesh-fix
Mar 17, 2026
Merged

fix: correct mesh packet construction, AES wire format, and node offl…#13
retsimx merged 1 commit into
mainfrom
mesh-fix

Conversation

@retsimx

@retsimx retsimx commented Mar 17, 2026

Copy link
Copy Markdown
Owner

…ine detection

mesh_construct_packet wrote vendor_id via struct field assignment, leaving the alignment padding byte (MeshPkt offset 21) as zero. parse_ble_packet_op_params reads through the flat val[] overlay, so vendor_id_lo landed in the padding slot as 0x00, causing every mesh command to be silently discarded. Fix: write op/vendor_id/params through att_cmd_mut().value.val[] directly.

A prior fix changed MeshPkt.vendor_id from u16 to [u8;2] to eliminate the padding, which shifted internal_par2 from offset 40 to 39 and shrunk the broadcast AES payload from 0x1c to 0x1b bytes. Old firmware always uses 0x1c, so cross-firmware broadcast decryption broke. Fix: revert vendor_id to u16.

mesh_node_flush_status computed elapsed time as a u32 subtraction of two values that are semantically u16 (system tick >> 16). After the 16-bit counter wraps (~134 s at 32 MHz) the subtraction underflows to ~4.3e9, exceeding the 1464-tick timeout threshold and simultaneously falsely expiring every node. Fix: wrapping_sub as u16, then widen to u32. LLVM emits (a-b)&0xFFFF; verified in the tc32 assembly output of a clean firmware build.

mesh_node_update_status accepted sn_difference==0 and refreshed the node tick. Neighbours re-broadcast a powered-off node's last state indefinitely with its frozen sn, so the coordinator's timeout clock was permanently reset and offline notifications never fired. Fix: require sn_difference>0 to accept any update. Live nodes call mesh_node_keep_alive before each advertisement, guaranteeing a monotonically advancing sn; dead nodes produce only stale relays with a fixed sn.

…ine detection

mesh_construct_packet wrote vendor_id via struct field assignment, leaving the
alignment padding byte (MeshPkt offset 21) as zero. parse_ble_packet_op_params
reads through the flat val[] overlay, so vendor_id_lo landed in the padding
slot as 0x00, causing every mesh command to be silently discarded. Fix: write
op/vendor_id/params through att_cmd_mut().value.val[] directly.

A prior fix changed MeshPkt.vendor_id from u16 to [u8;2] to eliminate the
padding, which shifted internal_par2 from offset 40 to 39 and shrunk the
broadcast AES payload from 0x1c to 0x1b bytes. Old firmware always uses 0x1c,
so cross-firmware broadcast decryption broke. Fix: revert vendor_id to u16.

mesh_node_flush_status computed elapsed time as a u32 subtraction of two
values that are semantically u16 (system tick >> 16). After the 16-bit counter
wraps (~134 s at 32 MHz) the subtraction underflows to ~4.3e9, exceeding the
1464-tick timeout threshold and simultaneously falsely expiring every node.
Fix: wrapping_sub as u16, then widen to u32. LLVM emits (a-b)&0xFFFF; verified
in the tc32 assembly output of a clean firmware build.

mesh_node_update_status accepted sn_difference==0 and refreshed the node tick.
Neighbours re-broadcast a powered-off node's last state indefinitely with its
frozen sn, so the coordinator's timeout clock was permanently reset and offline
notifications never fired. Fix: require sn_difference>0 to accept any update.
Live nodes call mesh_node_keep_alive before each advertisement, guaranteeing a
monotonically advancing sn; dead nodes produce only stale relays with a fixed sn.
@github-actions

Copy link
Copy Markdown

📊 Coverage Report

Metric Coverage
Lines 99.88%
Functions 100.00%
Regions 99.78%
Branches 93.96%

@retsimx
retsimx merged commit 51fdba3 into main Mar 17, 2026
5 checks passed
@retsimx
retsimx deleted the mesh-fix branch March 17, 2026 23:25
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.

1 participant