Skip to content

Take the packet end from the length field, not a suffix search - #711

Open
InDate wants to merge 1 commit into
codetheweb:masterfrom
InDate:fix/3.5-suffix-search
Open

InDate wants to merge 1 commit into
codetheweb:masterfrom
InDate:fix/3.5-suffix-search

Conversation

@InDate

@InDate InDate commented Oct 20, 2026 •

Copy link
Copy Markdown

Summary

parsePacket searched for the suffix from byte 0. The sequence field sits inside that range, so a sequence number of 0x0000AA55, or 0x00009966 on 3.5, produces a match there. The buffer is cut to 8 or 10 bytes, and the next readUInt32BE throws ERR_OUT_OF_RANGE. Every device whose counter reaches those values drops that frame.

 parsePacket(buffer)
   prefix = buffer.readUInt32BE(0)
-  suffixLocation = buffer.indexOf('0000AA55') ?? buffer.indexOf('00009966')
-  cut buffer at suffixLocation + 4
+  frameLength = prefix === 0x6699
+    ? buffer.readUInt32BE(14) + 22   // header 18 + length + suffix 4
+    : buffer.readUInt32BE(12) + 16   // header 16 + length
+  buffer shorter than frameLength -> throw "Packet missing payload"
+  cut buffer at frameLength, rest to leftover
   suffix check, sequence, command, payload as before

The lengths match what _encodePre34, _encode34 and _encode35 write.

Evidence

Found on a 3.5 light, Version: 3.5:

The value of "offset" is out of range. It must be >= 0 and <= 6. Received 8

New tests in test/parser.js: for protocols 3.1, 3.3, 3.4 and 3.5 and sequence numbers 0xaa55 and 0x9966, two packets back to back parse as 2 packets, each with its sequence number, command and payload.

  • Before (master): 5 of the 8 fail with ERR_OUT_OF_RANGE: 0xaa55 on all four protocols, and 0x9966 on 3.5.
    After: npm test on Node 22.23.2: 47 tests passed. npm run lint: 0 errors, the same 2 warnings as master; the parsePacket complexity warning moves from 31 to 32.

The patched build has run on a Homey Pro with 3.3 and 3.5 devices, and the light reports its state as before.

Merge Danger

Door: two-way

Blast Radius: parsing

Every received frame now goes through the length field. A device whose length field disagrees with its actual frame size used to parse when the suffix sat at the end. With this change it throws "Packet missing payload", or its trailing bytes go to leftover. The encoders and the existing payload-size checks already depend on that field.

https://claude.ai/code/session_01Mi7yrmdxpownpnTsMGLHJW

parsePacket located the frame end with buffer.indexOf('0000AA55'), then
'00009966', searched from byte 0. A sequence number of 0x0000AA55, or
0x00009966 on protocol 3.5, holds those bytes at offset 4 or 6, so the
search returns the sequence field, the buffer is cut to 8 or 10 bytes,
and the next readUInt32BE throws ERR_OUT_OF_RANGE ("must be >= 0 and
<= 6. Received 8" on 3.5). Every device whose counter passes those
values drops that frame.

The frame length now comes from the header: 16 + length for 55AA
frames, 22 + length for 6699 frames, matching what the encoders write.
Bytes past it go to leftover as before; a buffer shorter than it throws
"Packet missing payload".

Tests cover 3.1, 3.3, 3.4 and 3.5 with both sequence numbers, two
packets back to back. Five of the eight fail on master.

Claude-Session: https://claude.ai/code/session_01Mi7yrmdxpownpnTsMGLHJW

This branch has not been deployed

No deployments
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