CCSDS Space Packet Protocol (SPP), Encapsulation Packet Protocol (EPP), and File CLAs in ION
February 2026
Overview
ION provides three plugin-based Convergence Layer Adapters (CLAs) that use dynamic library loading to interface with provider libraries at runtime:
- SPP CLA: Space Packet Protocol CLA for transmitting bundles via CCSDS Space Packets (CCSDS 133.0-B-2)
- EPP CLA: Encapsulation Packet Protocol CLA for transmitting bundles via CCSDS Encapsulation Packets (CCSDS 734.20-O-1)
- File CLA: File-based CLA for transmitting bundles via file storage (store-and-forward / sneakernet scenarios)
All three CLAs use the same plugin architecture that allows users to provide their own provider libraries. ION includes stub/loopback libraries for testing purposes.
SPP CLA Description
In the CCSDS Bundle Protocol Version 7 Orange Book, the Bundle Protocol Agent (BPA) interacts with an underlying Space Packet service through the following service primitives:
- OCTET_STRING.request (Octet String, APID, Secondary Header Indicator, Packet Type, Packet Sequence Count/Packet Name)
- OCTET_STRING.indication (Octet String, APID, Secondary Header Indicator, Data Loss Indicator (optional))
SPP Constraints
- Maximum bundle size: 65,536 bytes (minus the size of packet secondary header)
- Octet string shall be a single CBOR serialized bundle
- The specific link destination determines the APID
- Packet Secondary Header Indicator shall be set to absent
- Packet Sequence Count shall always be used instead of a Packet Name
NOTE: Additional configuration and service limitations for an SPP provider instance can be found in ANNEX B of the CCSDS BPv7 Orange Book.
EPP CLA Description
The Encapsulation Packet Protocol provides a simpler interface for transmitting bundles over CCSDS Space Data Link Protocol (SDLP) channels. The service primitives are:
- ENCAPSULATION.request (Data, Length, SDLP Channel, EPI)
- ENCAPSULATION.indication (Data, SDLP Channel, EPI)
EPP Characteristics
- Maximum bundle size: 4,294,967,287 bytes per CCSDS 734.20-O-1 (ION uses a practical 1MB buffer)
- Encapsulation Protocol Identifier (EPI) for Bundle Protocol: 4 (registered in SANA)
- Simpler than SPP with no sequence counting required at the CLA level
File CLA Description
The File CLA enables bundle transmission via file storage, supporting store-and-forward and "sneakernet" scenarios where bundles are physically transported via storage media.
File CLA Characteristics
- Use case: Store-and-forward, air-gapped networks, removable media transport
- Provider library: Handles file I/O, framing, and integrity checking
- Flexible file modes: Same file (loopback) or separate files (send/receive)
- Polling-based receiver: CLI polls for new data at configurable intervals
Default Frame Format (Simple Provider)
The included libfile_simple_provider uses length-prefixed framing with CRC32 integrity checking:
+----------------+----------------+------------------+----------------+
| 4-byte length | 4-byte CRC32 | Bundle Data | 4-byte CRC32 |
| (big-endian) | (of length) | (N bytes) | (of bundle) |
+----------------+----------------+------------------+----------------+
- 12 bytes overhead per bundle
- Length CRC: Detects corrupt length before attempting large reads
- Data CRC: Ensures bundle integrity after storage/transport
- Standard CRC-32: IEEE 802.3 polynomial (0x04C11DB7)
Design Considerations
- In actual deployment, the provider is external software/hardware available in a user's platform
- The CLAs use dynamic library loading (
dlopen) to interface with provider libraries at runtime - The provider library handles the means of transferring data (TCP, UDP, serial, SpaceWire, file I/O, etc.)
- The CLA is not responsible for configuring communications below the protocol layer
Architecture Overview
Sender Side: - BP → CLA (sppclo/eppclo/fileclo) → Provider Library → Underlying Transport/Storage
Receiver Side: - BP ← CLA (sppcli/eppcli/filecli) ← Provider Library ← Underlying Transport/Storage
CLA Executables
SPP CLA
| Executable | Description |
|---|---|
sppcli |
SPP Convergence Layer Input daemon (receiver) |
sppclo |
SPP Convergence Layer Output daemon (sender) |
EPP CLA
| Executable | Description |
|---|---|
eppcli |
EPP Convergence Layer Input daemon (receiver) |
eppclo |
EPP Convergence Layer Output daemon (sender) |
File CLA
| Executable | Description |
|---|---|
filecli |
File Convergence Layer Input daemon (receiver) |
fileclo |
File Convergence Layer Output daemon (sender) |
Stub/Loopback Libraries for Testing
ION includes provider libraries that enable testing the CLAs without real hardware. These libraries are built when running make buildcheck.
Available Stub Libraries
| Library | Location | Description |
|---|---|---|
libspp_loopback_provider.so |
bpv7/spp/stub/.libs/ |
SPP loopback via named pipe |
libepp_loopback_provider.so |
bpv7/epp/stub/.libs/ |
EPP loopback via named pipe |
libfile_simple_provider.so |
bpv7/file/stub/.libs/ |
File I/O with CRC32 framing |
Running the Loopback/Test Scripts
# From the ION build directory
# SPP Loopback Test
cd tests/loopback-spp
./dotest
# EPP Loopback Test
cd tests/loopback-epp
./dotest
# File CLA Loopback Test (same file for send/receive)
cd tests/loopback-file
./dotest
# File CLA Transfer Test (separate files, simulates sneakernet)
cd tests/file-transfer
./dotest
Configuration in bprc
Adding the Protocol
# For SPP (payload_bytes, overhead_bytes)
a protocol spp 1400 100
# For EPP
a protocol epp 1400 100
# For File (payload_bytes, overhead_bytes)
a protocol file 65536 12
Adding Inducts (Receivers)
# SPP induct
a induct spp <duct_name> 'sppcli <duct_name> <library_path>'
# EPP induct
a induct epp <duct_name> 'eppcli <duct_name> <library_path>'
# File induct
a induct file <duct_name> 'filecli <duct_name> <library_path> <input_file_path> [poll_interval_ms]'
Adding Outducts (Senders)
# SPP outduct - config format: APID,seq_count,packet_type,sec_header_flag
a outduct spp <duct_name> 'sppclo <duct_name> <library_path> <apid>,<seq_count>,<packet_type>,<sec_header_flag>'
# EPP outduct
a outduct epp <duct_name> 'eppclo <duct_name> <library_path> <sdlp_channel>'
# File outduct
a outduct file <duct_name> 'fileclo <duct_name> <library_path> <output_file_path>'
Configuration Parameters
SPP Configuration Parameters
| Parameter | Description | Valid Values |
|---|---|---|
apid |
Application Process ID | 0-2047 (11 bits) |
seq_count |
Initial sequence count | 0-16383 (14 bits, auto-increments) |
packet_type |
Packet type | 0=TM, 1=TC |
sec_header_flag |
Secondary header flag | 0=absent, 1=present |
EPP Configuration Parameters
| Parameter | Description |
|---|---|
sdlp_channel |
SDLP channel identifier (mission-specific integer) |
File CLA Configuration Parameters
| Parameter | Description | Default |
|---|---|---|
library_path |
Path to the provider shared library | (required) |
input_file_path |
File path for CLI to read bundles from | (required for CLI) |
output_file_path |
File path for CLO to write bundles to | (required for CLO) |
poll_interval_ms |
How often CLI checks for new data (milliseconds) | 1000 |
Example Configurations
SPP Loopback Example (bprc)
1
a scheme ipn 'ipnfw' 'ipnadminep'
a endpoint ipn:1.1 q
a protocol spp 1400 100
a induct spp loopback 'sppcli loopback /path/to/libspp_loopback_provider.so'
a outduct spp loopback 'sppclo loopback /path/to/libspp_loopback_provider.so 123,0,0,0'
EPP Loopback Example (bprc)
1
a scheme ipn 'ipnfw' 'ipnadminep'
a endpoint ipn:1.1 q
a protocol epp 1400 100
a induct epp loopback 'eppcli loopback /path/to/libepp_loopback_provider.so'
a outduct epp loopback 'eppclo loopback /path/to/libepp_loopback_provider.so 42'
File CLA Loopback Example (bprc)
1
a scheme ipn 'ipnfw' 'ipnadminep'
a endpoint ipn:1.1 q
a protocol file 65536 12
a induct file loopback 'filecli loopback /path/to/libfile_simple_provider.so /tmp/bundles.dat 500'
a outduct file loopback 'fileclo loopback /path/to/libfile_simple_provider.so /tmp/bundles.dat'
File CLA Store-and-Forward Example (bprc)
For separate send/receive files (sneakernet scenario):
1
a scheme ipn 'ipnfw' 'ipnadminep'
a endpoint ipn:1.1 q
a protocol file 65536 12
# CLI reads from inbound file
a induct file transfer 'filecli transfer /path/to/libfile_simple_provider.so /mnt/usb/inbound.dat 500'
# CLO writes to outbound file
a outduct file transfer 'fileclo transfer /path/to/libfile_simple_provider.so /mnt/usb/outbound.dat'
Configuration in ipnrc
Add egress plans to route bundles through the outducts:
# For SPP
a plan <destination_node> spp/<duct_name>
# For EPP
a plan <destination_node> epp/<duct_name>
# For File
a plan <destination_node> file/<duct_name>
Example ipnrc Configuration
Implementing a Custom Provider Library
To use these CLAs with real hardware or custom transport, implement a provider library that exports the required functions.
SPP Provider Library Functions
void init_space_packet_sender(void);
void finalize_space_packet_sender(void);
int packet_request(unsigned char *buffer, int apid, int seq_count,
int packet_type, int sec_header_flag, size_t total_length);
size_t packet_indication(char *buffer, int *received_apid);
EPP Provider Library Functions
void init_epp_sender(void);
void finalize_epp_sender(void);
int encapsulation_request(unsigned char *data, size_t length,
int sdlp_channel, int epi);
size_t encapsulation_indication(char *buffer, int *sdlp_channel, int *epi);
File Provider Library Functions
/* Initialize sender - called once at startup */
int init_file_sender(const char *file_path);
/* Cleanup sender - called at shutdown */
void finalize_file_sender(void);
/* Write a bundle to the file
* Returns: bytes written, or negative on error */
int file_write_bundle(unsigned char *data, size_t length);
/* Initialize receiver - called once at startup */
int init_file_receiver(const char *file_path, int poll_interval_ms);
/* Cleanup receiver - called at shutdown */
void finalize_file_receiver(void);
/* Read a bundle from the file
* Returns: >1 = bytes read, 1 = normal stop, 0 = error */
size_t file_read_bundle(char *buffer);
Building Your Provider Library
# Linux
gcc -shared -fPIC -o libmyprovider.so myprovider.c
# macOS
gcc -shared -fPIC -o libmyprovider.dylib myprovider.c
Compatibility Notes
- Embedded RTOS: FreeRTOS does not support
dlopen. Custom embedded Linux systems (Yocto, Buildroot) should work. - Security: Security mechanisms may need configuration to allow
dlopen(e.g., SELinux). - Dependencies: Any libraries used by your provider must be available when running the CLA daemons.
Test Configurations
| Configuration | Location |
|---|---|
| SPP Loopback Test | tests/loopback-spp/ |
| EPP Loopback Test | tests/loopback-epp/ |
| File Loopback Test | tests/loopback-file/ |
| File Transfer Test | tests/file-transfer/ |
| SPP Two-Node Demo | configs/two-node-spp/ |
| SPP Loopback Config | configs/loopback-spp/ |
| EPP Loopback Config | configs/loopback-epp/ |