Skip to content

feat(kble-c2a): fragment oversized Space Packets across AOS Transfer Frames#178

Open
Kentaro Sugimoto (tarotene) wants to merge 2 commits into
mainfrom
feat/kble-c2a-spacepacket-aos-tf-fragmentation
Open

feat(kble-c2a): fragment oversized Space Packets across AOS Transfer Frames#178
Kentaro Sugimoto (tarotene) wants to merge 2 commits into
mainfrom
feat/kble-c2a-spacepacket-aos-tf-fragmentation

Conversation

@tarotene
Copy link
Copy Markdown

Summary

kble-c2a spacepacket to-aos-tf previously assumed one Space Packet (SP) fits
entirely in one AOS Transfer Frame. This violates CCSDS 732.0-B-4 §4.1.4, which
defines the M_PDU First Header Pointer (FHP) mechanism to support SP spanning
across multiple frames. The command now implements that mechanism.

An additional latent bug is fixed simultaneously: SP sizes in the range
[426, 432] passed the explicit upper-bound check but then caused a usize
underflow when computing the trailing Idle Packet length, producing either a
panic (debug) or a malformed 444-byte frame with Packet Data Length = 0xFFFF
(release).

Behaviour change matrix

Each row shows the total SP length L against kble-c2a spacepacket to-aos-tf.

L Frames emitted Before After Status
7 1 Valid 1 TF Valid 1 TF (byte-identical) OK → OK
44 1 Valid 1 TF Valid 1 TF (byte-identical) OK → OK
136 1 Valid 1 TF Valid 1 TF (byte-identical) OK → OK
425 1 Valid 1 TF (Idle data = 1 B) Valid 1 TF (byte-identical) OK → OK
432 2 Crash — debug: panic on usize underflow; release: writes 444 B frame with malformed Idle Packet (Packet Data Length = 0xFFFF, 0 data bytes) 2 valid TFs: full-SP frame (FHP = 0) + Idle-only frame (FHP = 0) NG → OK
433 2 Err("Space Packet is too large: 433 bytes") 2 valid TFs: 432 B fragment + 1 B fragment with Idle (FHP = 1) NG → OK
649 2 Err 2 valid TFs: 432 + 217 B remainder (FHP = 217) NG → OK
864 3 Err 3 valid TFs: 432 + 432 + Idle-only (FHP = 0) NG → OK
1024 3 Err 3 valid TFs: 432 + 432 + 160 B (FHP = 160) NG → OK
858 3 Err 3 valid TFs via prepend-Idle path: Idle(7)+SP[0..425] / SP[425..857] / SP[857..858]+Idle(431) NG → OK
863 3 Err Same prepend-Idle path, tail SP = 6 B NG → OK
2048 5 Err 5 valid TFs: 432×4 + 320 B remainder NG → OK

Supporting observations

  • frame_count now increments once per emitted AOS TF (not per input SP), matching the continuous-per-VC requirement of CCSDS 732.0-B-4 §4.1.2.4. Single-frame cases (L ≤ 425) still increment by 1, preserving existing behaviour.
  • L ∈ [426, 431] was a silently broken band: the release build emitted a 444-byte frame with a corrupt Idle Packet. This is repaired without changing the single-frame output for L ≤ 425.
  • L < 7 is now explicitly rejected with Err("Space Packet is too short: {L} bytes"). Previously, such input produced a TF with no valid SP content.

Fragmentation algorithm

Three cases based on L and r = L mod 432:

  • Case A (L ≤ 425): single TF, [SP | Idle(432−L)], FHP = 0. Output preserved byte-for-byte.
  • Case B (L > 425, r ∈ {0} ∪ [1..=425]): emit full 432-byte SP chunks (FHP = 0x07FF for continuation), then a tail frame with [SP_remainder | Idle(432−r)] at FHP = r. When r = 0, append a dedicated Idle-only TF (FHP = 0).
  • Case C (r ∈ [426..=431]): a naive tail would leave fewer than 7 bytes for the Idle Packet, violating CCSDS 133.0-B-1. A minimum 7-byte Idle Packet is prepended to the first frame, shifting the SP start from offset 0 to offset 7. This moves the effective tail remainder from [426..=431] to [1..=6], restoring CCSDS compliance.

Test plan

  • cargo test -p kble-c2a — 14 new tests pass (all 19 total, including 5 pre-existing tfsync tests)
  • cargo clippy -p kble-c2a -- -D warnings — no warnings
  • For L ≤ 425: sp_bit_identical_to_legacy asserts byte-for-byte equality with the output of the previous implementation
  • Round-trip SP reconstruction verified for all multi-frame cases via assert_sp_round_trip
  • Idle Packet structural validity (APID = 0x7FF, correct Packet Data Length field) verified for all trailing and prepended Idle Packets

References

  • CCSDS 732.0-B-4 §4.1.4: Multiplexing Protocol Data Unit (M_PDU) — First Header Pointer and packet spanning
  • CCSDS 133.0-B-1 §4.1.3: Space Packet structure — minimum packet size (7 octets)

🤖 Generated with Claude Code

…Frames

Per CCSDS 732.0-B-4 §4.1.4, a Space Packet (SP) may span multiple AOS
Transfer Frames via the M_PDU First Header Pointer (FHP) mechanism.
The previous implementation rejected any SP larger than the M_PDU Data
Zone (432 bytes) with an error, and also contained a latent
underflow for SP sizes in [426, 432] where the trailing Idle Packet
would become malformed.

This commit rewrites `to_aos_tfs` (renamed from `to_aos_tf`) to emit
one or more 444-byte AOS TFs per input SP:

- Case A (L <= 425): single TF, SP + Idle Packet -- behaviour preserved
  byte-for-byte (asserted by a golden test).
- Case B (L > 425, L mod 432 in {0} union [1..=425]): full 432-byte SP
  chunks with FHP = 0x07FF (No Header) for continuation frames;
  final frame has FHP pointing to the trailing Idle Packet; when SP
  ends exactly on a Data Zone boundary, a dedicated Idle-only TF
  (FHP = 0) is appended.
- Case C (L mod 432 in [426..=431]): a minimum 7-byte Idle Packet is
  prepended to the first frame to shift the SP start by 7 bytes, which
  moves the tail remainder back into [1..=6] -- a region where the
  trailing Idle Packet satisfies the CCSDS 133.0-B-1 minimum size.

frame_count advances once per emitted AOS TF (not per input SP),
which is the continuous-per-VC behaviour required by CCSDS 732.0-B-4
section 4.1.2.4.

The caller run_sp_to_aos_tf is updated to iterate over the returned
Vec<BytesMut> and send each frame individually.

Fourteen unit tests cover the full size matrix, including pathological
sizes, exact Data Zone multiples, round-trip SP reconstruction, Idle
Packet structural validity, and frame_count wrapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tarotene Kentaro Sugimoto (tarotene) force-pushed the feat/kble-c2a-spacepacket-aos-tf-fragmentation branch from b0caee7 to a089fca Compare April 21, 2026 05:12
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