Thomas Gazagnaire

Thomas Gazagnaire

Building Functional Systems from Cloud to Orbit. thomas@gazagnaire.org

Reimplementing the Space Protocol Stack from Scratch

2026-04-15

A satellite link is a radio signal between a ground station and a spacecraft moving at 7.5 km/s, visible for 10 minutes at a time, over a channel measured in kilobits per second. If you have used TCP/IP, the protocol structure will look familiar: there is a transport layer that handles reliability, a network layer that handles addressing, and an application layer where the actual data lives. The difference is the link.

The protocol suite that handles this is CCSDS (Consultative Committee for Space Data Systems), a set of standards maintained since 1982 by NASA, ESA, JAXA, and most other space agencies. Nearly every satellite launched in the last 30 years speaks some subset of CCSDS. If you want to talk to a satellite, this is the stack you need to understand.

Most implementations are proprietary C libraries inside ground segment frameworks. I wanted something I could test in a browser.

So I have been implementing these protocols in OCaml using the typed binary codec approach I described in the wire formats post. The demo below runs the real parser in the browser, so you can play with the encodings directly. Type a message and watch it get wrapped into a telemetry frame (Space Packet inside a TM frame, exactly as a satellite would transmit it). Hover any byte in the hex dump to see which protocol field it belongs to.

Hex dump (editable)

Decoded layers (hover to highlight bytes)

The layers

CCSDS protocols were designed to run on spacecraft with kilobytes of RAM, fixed-point processors, and no operating system. The formats are deliberately simple: small headers, fixed fields, no optional extensions, no negotiation. A flight computer from the 1990s can parse them. The layers that matter for most missions are described in the Blue Books (the ratified standards). The newer stuff (recommended practices like delay-tolerant networking) lives in the Magenta Books, and the really new stuff (experimental specifications like post-quantum crypto) in the Orange Books.

Space Communications Protocols Reference Model
The CCSDS protocol reference model (Figure 2-1 from CCSDS 130.0-G-4), suggested by Virgile Robles.

From top to bottom:

Space Packets are the application-layer unit (CCSDS 133.0-B-2). A Space Packet is a 6-byte header followed by up to 65,536 bytes of data. The header contains a version number, an application identifier (APID, 11 bits), a sequence counter (14 bits), and the data length. That is it. No checksums, no encryption, no retry logic. Space Packets are deliberately simple because everything else is handled by the layers below.

Transfer Frames carry Space Packets over the radio link. There are two classic flavours: TM frames (CCSDS 132.0-B-3) for telemetry (satellite to ground) and TC frames (CCSDS 232.0-B-4) for telecommand (ground to satellite). A TM frame has a 6-byte header with a spacecraft ID (10 bits), a virtual channel ID (3 bits), and two frame counters. TC frames are similar but smaller, designed for low-bandwidth uplinks. Both carry Space Packets as payload.

Two newer frame types exist for missions that need more flexibility: AOS (CCSDS 732.0-B-4) adds an 8-bit spacecraft ID and 6-bit virtual channel ID with a 24-bit frame counter, and USLP (CCSDS 732.1-B-2) unifies all four frame types into a single format with a 16-bit spacecraft ID.

Security sits between the frame header and the frame data. SDLS (CCSDS 355.0-B-2) adds authentication (MAC), encryption (AES-GCM), and anti-replay protection. Without SDLS, anyone with a dish and the right frequency can send commands to a spacecraft. With SDLS, every command is authenticated and every telemetry frame is encrypted.

Reliability is handled by COP-1 (part of CCSDS 232.1-B-2), a retransmission protocol for telecommand. The ground sends a command, the spacecraft acknowledges receipt via a CLCW (Command Link Control Word) embedded in the next telemetry frame. If the acknowledgement is missing, the ground retransmits. This is where the 10-minute pass window hurts most: every missed acknowledgement costs seconds that cannot be recovered.

How they compose

A typical downlink looks like this: the application generates data, wraps it in a Space Packet (6-byte header + payload), the packet is placed inside a TM frame (6-byte frame header + packet + optional error-correction trailer), SDLS encrypts and authenticates the frame, and the frame is transmitted over the radio link. The ground station receives the signal, decrypts the frame, extracts the packet, and delivers the data to the mission control system.

A typical uplink is the reverse: the operator creates a command, wraps it in a Space Packet, places it in a TC frame, SDLS authenticates it, and the frame is transmitted during the next pass window. COP-1 handles retransmission if the spacecraft does not acknowledge.

The key insight is that each layer is independent. The Space Packet does not know whether it is riding inside a TM frame or a USLP frame. The security layer does not know what the packet contains. This is the same separation that makes TCP/IP work: you can replace Ethernet with Wi-Fi without changing HTTP.

The OCaml implementation

Each layer described above has its own library (one per frame type, plus security and the feedback word):

Protocol Library CCSDS spec
Space Packets space-packet 133.0-B-2
TM frames tm 132.0-B-3
TC frames tc 232.0-B-4
AOS frames aos 732.0-B-4
USLP frames uslp 732.1-B-2
Security (SDLS) sdls 355.0-B-2
Feedback word (CLCW) clcw 232.1-B-2

I also have implementations of the file delivery protocol (CFDP), the ground station interface (SLE), the delay-tolerant networking stack for deep-space missions (Bundle Protocol, LTP, Contact Graph Routing), and most of the other Blue Book protocols. I will write more about them in the coming months and release the code properly on GitHub once the APIs stabilise.

All the libraries in the table use ocaml-wire to generate parsers and serialisers from a single typed definition. The wire description is the specification: a typo in a field width is a type error, not a runtime bug.

The parser descriptions are pure OCaml with no system dependencies. The same definitions compile to JavaScript via js_of_ocaml and to verified C via EverParse. The demo above runs the real space-packet parser in your browser, and the SDLS crypto! The same code runs in the test harness on my laptop. The EverParse path is still work in progress, but the generated C is zero-copy and allocation-free, so there is no obvious blocker to embedding it on a constrained target once the right glue code is written. Building for the browser first meant I could encode a frame, tweak a field, and watch the hex change before writing a single test. Same compilation story as the CSS engine and the conjunction assessment dashboard.

Each library has an alcotest suite with hand-written cases drawn from the blue book examples, plus round-trip fuzz tests using Alcobar (a Crowbar fork with an Alcotest-compatible API). The fuzz tests caught real bugs (an OCF/FECF masking error in the AOS encoder, for instance).

Several libraries have interoperability suites that round-trip frames against external implementations: SDLS against NASA CryptoLib 1.5.1 (byte-identical TC frames with AES-256-GCM), USLP against spacepackets-py (18 reference frames), LTP against NASA JPL's ION 4.1.4 (SDNV encoding), and CFDP against both spacepackets-py and dariol83/ccsds (Java). The CFDP interop tests found a byte-order bug in spacepackets-py 0.31.0, which is already fixed: KeepAlivePdu.pack() was using native endian instead of big-endian for the progress field, producing wrong bytes on every x86 and ARM machine. The CryptoLib interop tests also surfaced questions about IV handling in AOS that may be related to a confirmed bug in SA Create. More interop suites are in progress.

The wire approach I described in an earlier post is what keeps these parsers compact and correct across every layer. The whole stack is open source and being developed at Parsimoni as part of a larger effort to bring modern tooling to satellite software. If any of this is useful to you, do drop me a line -- I would love to hear about it.

References

Related Posts