Commit Graph

91 Commits

Author SHA1 Message Date
Matthew Wolter
d98523cddb G1: N08 + F12 + N10 — cosmetic cleanup in reader.py
Three small cleanup fixes bundled per proposal §4.1 commit order.

N08 — CONTROL_DATA empty payload guard. The handler reads
`payload = dbuf.read()` then immediately dereferences `payload[0]`
without checking length. A zero-length payload (firmware truncation
or garbled frame) raises IndexError. Pre-F06 the IndexError would
escape; post-F06 it would log and skip the dispatch via the umbrella.
Adding an explicit `if len(payload) == 0: return` after the read
short-circuits the empty case before it touches `payload[0]`, with a
debug log noting the empty payload. The `return` exits handle_rx
cleanly without engaging the F06 umbrella's parse-error path, which
is the correct behavior — an empty CONTROL_DATA frame is not a parse
error, it's an unusable frame.

F12 — print(res) leftover debug. The RAW_DATA handler had a stray
`print(res)` polluting stdout. Replaced with `logger.debug(res)` to
match the surrounding `logger.debug("Received raw data")` line.

N10 — magic numbers 16 and 17. Two `elif packet_type_value == 16/17`
branches hardcoded the integer values for CONTACT_MSG_RECV_V3 and
CHANNEL_MSG_RECV_V3, both already declared in packets.py:94-95.
Replaced with `PacketType.CONTACT_MSG_RECV_V3.value` and
`PacketType.CHANNEL_MSG_RECV_V3.value` to eliminate drift risk if
the enum is ever renumbered.

Findings: N08 (Info), F12 (Info), N10 (Info)
File: src/meshcore/reader.py
2026-04-11 18:33:20 -07:00
Matthew Wolter
a571eff4ce G1: NEW-C — add length guard to STATUS_RESPONSE push handler
Why: parse_status with offset=8 reads up through data[56:60]
(the rx_airtime field), so a full STATUS_RESPONSE push frame is
60 bytes: 1 type + 1 reserved + 6 pubkey + 52 status fields. The
push handler in handle_rx previously called parse_status with no
length check at all, so a short frame would slice through empty
data and silently produce zeros for every missing field. HA sensor
telemetry would silently report all-zero status — same class as N07.

The BINARY_RESPONSE STATUS path at the bottom of handle_rx already
gates parse_status with `len(response_data) >= 52` on its
offset-stripped buffer; this commit adds the equivalent gate for
the push path: `if len(data) < 60: log + return`. The `return`
short-circuits cleanly out of the umbrella try block without
dispatching a STATUS_RESPONSE event for the bogus parse.

Refs: Forensics report finding NEW-C (S3)
2026-04-11 18:21:27 -07:00
Matthew Wolter
3273c3489c G1: N07 — tighten BATTERY storage-field length guard
Why: The BATTERY handler previously gated the used_kb / total_kb
reads on `len(data) > 3`, which is wrong. The full
RESP_CODE_BATT_AND_STORAGE frame is 11 bytes (1 type + 2 level +
4 used_kb + 4 total_kb), so a 4-10 byte truncated frame would pass
the guard, and io.BytesIO.read(4) silently returns short bytes
instead of raising. int.from_bytes(b"", ...) returns 0, so HA
sensor telemetry silently reports zero storage on a truncated frame.

Tighten the guard to `len(data) >= 11` so the storage fields are
only parsed when the full frame is present. Inline comment added
to document the expected frame layout.

Note: the unconditional 2-byte `level` read at the top of the
handler has the same class of issue (no guard, silent zero on a
1-byte frame). That is out of scope for finding N07 and has been
logged in issues_log.md as a separate item.

Refs: Forensics report finding N07 (S3)
2026-04-11 18:19:52 -07:00
Matthew Wolter
a7e257c78d G1: F11 — replace broken except e: in ALLOWED_REPEAT_FREQ handler
Why: The ALLOWED_REPEAT_FREQ branch in handle_rx had `except e:` —
syntactically valid Python only if `e` happens to be bound to an
exception class, which it isn't. The first time the inner read loop
actually raised, the except clause itself would raise NameError
("name 'e' is not defined") and propagate out of the handler. The
proposal correctly notes this is unreachable in practice today
because `int.from_bytes(b"", ...)` returns 0 so the loop terminates
cleanly, but it is a latent footgun. Replace with the standard
`except Exception as e:` form and swap the `print(e)` for a proper
`logger.warning(...)` call to match the rest of the file (which uses
the module logger, not stdout).

Refs: Forensics report finding F11 (S3)
2026-04-11 18:17:17 -07:00
Matthew Wolter
2025cb5326 G1: F10 — fix pbuf NameError in PUSH_CODE_LOGIN_FAIL handler
Why: The LOGIN_FAILED handler in handle_rx referenced an undefined
identifier `pbuf` instead of the local BytesIO `dbuf`. Firmware emits
PUSH_CODE_LOGIN_FAIL as a fixed 8-byte frame, which trivially
satisfies the `len(data) > 7` guard, so every remote auth failure
raised NameError. The sibling LOGIN_SUCCESS handler a few lines above
already uses `dbuf.read(6).hex()` correctly; this commit aligns the
LOGIN_FAILED branch with the same pattern.

Refs: Forensics report finding F10 (S1)
2026-04-11 18:15:29 -07:00
Matthew Wolter
d9197faf3a G1: F06 — wrap handle_rx dispatch in catch-all try/except
Why: handle_rx is invoked from a detached task in MessageReader, so any
exception escaping its ~850-line if/elif dispatch is silently swallowed
by asyncio as "Task exception was never retrieved." The only crash
guard previously was a single try/except IndexError around the first
byte read; everything past line 73 was unguarded. This commit adds an
umbrella try: ... except Exception as e: around the entire dispatch
body that logs the exception class, message, raw frame hex, and full
traceback via logger.error. The umbrella neutralizes the crash surface
of F10, F11, N07, N08, R01, NEW-B, and NEW-C, which the next commits
will then fix individually now that they are observable.

Refs: Forensics report finding F06 (umbrella crash protection)
2026-04-11 18:06:53 -07:00
Jack Kingsman
3ad77d364d Fix three byte path packets 2026-03-18 17:31:17 -07:00
Florent
5bfe63912c set decrypt_channel_logs to False by default 2026-03-11 10:21:29 -04:00
Florent
18528f2ed3 make a class and module for parsing meshcore packets 2026-03-09 18:22:02 -04:00
Florent
f3fce820fc fix error 2026-03-08 15:11:24 -04:00
Florent
cda44ae0a0 and if error message does not exist yet 2026-03-07 21:13:30 -04:00
Florent
fe2239a8c6 add code_string to error event 2026-03-07 21:05:00 -04:00
Florent
462c4311d3 implement advert_path 2026-03-07 17:42:41 -04:00
Florent
c378319252 some work on multibytes 2026-03-06 10:40:14 -04:00
Florent
f57cb66277 fix silly bug 2026-03-06 08:27:26 -04:00
Florent
563cbfbade complet channel log rx and use timestamp to calculate hashes 2026-03-05 21:32:24 -04:00
Florent
a83956ec1f some optimizations 2026-03-05 15:37:54 -04:00
Florent
322736024a fix 2026-03-05 14:53:43 -04:00
Florent
91be955044 error when msg_hash was not here 2026-03-05 14:41:19 -04:00
Florent
9f66885594 verify if channels has hashes ... 2026-03-05 13:56:29 -04:00
Florent
3d47d6d8b2 if possible, add path and rssi to channel messages 2026-03-05 11:50:41 -04:00
Florent
b1abb8e4d3 extract some info from log_rx 2026-03-05 09:32:19 -04:00
Florent
3716ebf77e handle multibytes in path discovery 2026-02-27 08:59:17 -04:00
Florent
f2def83f30 fix path len issue when getting contacts 2026-02-27 08:33:27 -04:00
Florent
dd6d6350d9 multibyte trace support 2026-02-26 22:51:52 -04:00
Florent
26730d1efa support path_hash_mode 2026-02-26 14:24:02 -04:00
Florent
3f56190423 Revert PR 45 2026-02-18 06:50:44 -04:00
Florent
8c33c09ac1 handle repeat mode 2026-02-14 15:36:17 -04:00
Florent
03a2a7c64e get/set repeat mode 2026-02-14 09:39:07 -04:00
Florent
ce6d14d618 disambiguate between anon and binary 2026-02-02 17:04:42 -04:00
Florent
d57162375a autoadd_config 2026-02-02 13:18:44 -04:00
Florent
3b46986dfa implemented anon binary requests 2026-02-02 11:55:18 -04:00
fdlamotte
a2d8b3e059 Merge pull request #48 from agessaman/add-recv-errors
add support for recv_errors in STATUS_PACKETS response
2026-01-30 10:48:11 -04:00
agessaman
ad7e48d028 add support for recv_errors in STATUS_PACKETS response 2026-01-29 20:41:48 -08:00
Michiel Appelman
0283003b04 Adds support for pull-based advert requests and responses. 2026-01-11 21:44:03 +01:00
agessaman
c42c30c25d implement device signing binary frames and sign() command for on-device signing. 2025-12-14 22:23:33 -08:00
fdlamotte
f7439ceac7 Merge pull request #35 from agessaman/main
Stats PacketType Cleanup
2025-11-25 07:35:17 +01:00
agessaman
e49d5c4c7b Fix residual packet types and rename STATS_CORE to STATS to match MyMesh.cpp 2025-11-24 17:41:17 -08:00
fdlamotte
3220c4196d Merge pull request #34 from agessaman/main
Companion Nodes Stats
2025-11-24 10:38:04 +01:00
agessaman
4a97dd0968 Modify statistics handling in MessageReader to support binary parsing for core, radio, and packet stats. Update DeviceCommands to send appropriate commands for each stats type. 2025-11-17 09:59:50 -08:00
Florent
26b8f2b340 reader: return and warns if packet is empty 2025-11-16 17:22:26 +01:00
Florent
307e517f5e req_neighbours 2025-11-09 16:51:54 +01:00
Florent
dea2f74eae fix snr values for incoming msgs 2025-11-08 08:17:34 +01:00
agessaman
f82ed89c02 Add support for new statistics event types and commands 2025-11-07 22:44:43 -08:00
Florent de Lamotte
a61616297e support only_prefix flag on discover node 2025-11-07 12:59:16 +01:00
Florent
d3c9c8d984 control codes support: node_discover_req 2025-11-07 09:59:40 +01:00
Florent de Lamotte
97a53ec32b most packets are now read using BytesIO 2025-11-05 13:37:38 +01:00
Florent de Lamotte
b8885e3015 starting rewriting of reader using io.BytesIO instead of fixed indexes 2025-11-05 13:11:48 +01:00
Florent de Lamotte
3ad3be82e7 support multiple_acks 2025-10-30 10:59:08 +01:00
Florent de Lamotte
d619423078 timeout for each contact in get_contacts 2025-10-22 10:21:07 +02:00