|
F439_CPP_TX-RX_LoRa_Project
|
The RadioLink protocol-verification harness exercises the hardened Wire v3 RX path with hostile and boundary-condition inputs.
The intent of this harness is to verify that RX continues operating safely when presented with malformed, malicious, replayed, or boundary-value frames, and to report a deterministic pass or fail result for every case.
The harness is a structured test suite. It transmits a fixed set of QA frames in a stable order, evaluates each received frame against an expected outcome, prints a per-test verdict, and emits a final tallied report.
The verification model intentionally separates roles:
This approach validates the real RX rejection path rather than a test-only RX parser. The RX side compares the parser's accept-or-reject outcome against the expected outcome recorded for each case and derives a PASS or FAIL verdict. Expected QA rejections are logged and must not invoke Error_Handler().
Protocol verification is enabled by defining:
#define RADIOLINK_QA_TEST
When enabled, Core/Src/main.c routes DIO1 EXTI events to QaApp_OnDio1Exti() and runs QaApp_Loop() instead of RadioApp_Loop(). The harness selects TX or RX behavior using sx1262Role. Both boards are flashed with the same QA-mode binary.
Under RADIOLINK_QA_TEST the node identifier used for crypto key derivation is fixed, so the TX and RX boards derive identical keys regardless of their hardware UID. This is required because the QA frame builders construct frames with a fixed node identifier.
Each QA frame is correlated to its test case by the msgCounter header field rather than by arrival order. TX encodes the case index into msgCounter (QA_RUN_BASE + caseIndex), and RX recovers the index from the cleartext header. Because the header is not encrypted, correlation works for both accepted and rejected frames, and a lost frame does not desync the suite.
The RX side also applies a per-test timeout. If a frame for a given case does not arrive within its deadline, that case is recorded as a FAIL with a "no frame received" reason and the suite advances. This guarantees the suite always completes and prints a final report.
During QA execution, TX sends one case per second in a stable order. TX logs the test name, sessionSeqId, msgCounter, frame length, and expected RX result before queuing each frame.
RX must:
For each received frame RX prints a test banner, the expected result, the parser outcome, and a PASS or FAIL verdict. After the final case RX prints a report giving the total, passed, and failed counts, and lists any failed tests by name.
When RADIOLINK_DEBUG_RX_REJECT_REASON_ENABLE is set, RadioLink_ParseWireV3Frame() logs which validation gate rejected a frame:
This makes the verdict meaningful at the gate level: a reject-expecting case is only fully trustworthy when it is rejected at the gate its corruption targets. The QA suite is expected to show truncated-frame, length-mismatch, oversized-payload, and invalid-nodeId rejected at gate=header, cmac-failure at gate=cmac, and replay-duplicate at gate=replay.
TX emits lines similar to:
QA TX: start test=truncated-frame sess=1 ctr=1000 expected=rejected: below minimum Wire v3 frame length QA TX: queued test=truncated-frame len=10 sess=1 ctr=1000 expected=rejected: below minimum Wire v3 frame length QA TX: done test=truncated-frame sess=1 ctr=1000 expected=rejected: below minimum Wire v3 frame length
RX emits a suite header, then per-test banners and verdicts, then a final report similar to:
[1/8] truncated-frame
expected : rejected: below minimum Wire v3 frame length
verdict : PASS
QA SUITE COMPLETE
Total tests : 8
Passed : 8
Failed : 0
Result : ALL PASS
The TX sequencer actively transmits the following cases in order:
Truncated Frame Rejection
A frame shorter than the minimum Wire v3 frame length is injected.
Expected RX behavior:
Frame Length Mismatch
A frame where the declared payload length does not match the received frame size is injected.
Expected RX behavior:
CMAC Authentication Failure
A validly structured frame with an intentionally corrupted authentication tag is injected.
Expected RX behavior:
Replay Rejection
The sequencer sends a valid replay seed frame and then sends an exact duplicate with the same nodeId, sessionSeqId, and msgCounter values.
Expected RX behavior:
Maximum Payload Boundary Acceptance
A frame containing RADIOLINK_WIRE_V3_MAX_PLAINTEXT_LEN plaintext bytes is transmitted.
Expected RX behavior:
Oversized Payload Rejection
A frame declaring a plaintext length larger than RADIOLINK_WIRE_V3_MAX_PLAINTEXT_LEN is injected.
Expected RX behavior:
Invalid NodeId Rejection
A frame whose nodeId byte is overwritten after frame construction is injected. The QA builder sets nodeId to 0xFF. Because the nodeId is covered by the CMAC, modifying it after the tag is computed invalidates the authentication tag.
Expected RX behavior:
Rejected protocol frames must be discarded without invoking Error_Handler().
The verified RX contract is:
The harness has one known limitation in this revision:
This verification work also establishes the categories that should eventually map to unique structured logging identifiers for remote syslog forwarding, for example: