LTE Core Network Emulator with satellite latency simulation.
SatCore is a protocol-level LTE EPC (Evolved Packet Core) emulator written in C that provides a complete data path from eNodeB through the core network to the internet or local resources. It features configurable tc/netem-based delay simulation for satellite link emulation (GEO, MEO, LEO, HEO orbits).
+-------+
| HSS |
| (S6a) |
+---+---+
|
+-------+ S1-MME +-------+ | S11 +-------+ S5 +-------+ SGi
| eNodeB |<-------------->| MME |<---+-------------->| SGW |<------------>| PGW |<---------> Internet
| | (S1AP) | | (GTPv2-C) | | (GTPv2-C) | | / Local
+---+---+ +-------+ +---+---+ (GTP-U) +---+---+ Resources
| | | (FTP, etc.)
| S1-U (GTP-U) | |
+------------------------------------------------------+ |
[tc/netem]
Delay Simulation
| Component | Binary | Description |
|---|---|---|
| MME | satcore_mme |
Mobility Management Entity - handles S1AP signaling, NAS procedures (attach, auth, security mode, detach), S11 session management, S1 handover orchestration, dedicated bearer setup |
| SGW | satcore_sgw |
Serving Gateway - GTPv2-C session management on S11/S5, GTP-U forwarding between eNB (S1-U) and PGW (S5-U), bearer management |
| PGW | satcore_pgw |
PDN Gateway - IP address allocation from configurable pool, GTP-U decapsulation, SGi routing to internet/local resources via TUN interface, NAT masquerading |
| HSS | satcore_hss |
Home Subscriber Server - CSV-based subscriber database, authentication vector generation (simplified Milenage), subscriber key management |
| eNodeB | satcore_enb |
eNodeB Emulator - S1AP procedures, GTP-U user plane, TUN interface for traffic injection, auto-attach configured UEs, handover support |
- GTPv2-C (3GPP TS 29.274): Create/Modify/Delete Session, Create Bearer (dedicated), F-TEID, Bearer Context, PAA, Cause IEs
- GTP-U (3GPP TS 29.281): G-PDU encapsulation/decapsulation, Echo Request/Response
- S1AP (3GPP TS 36.413): S1 Setup, Initial UE Message, Initial Context Setup, DL/UL NAS Transport, UE Context Release, Handover Required/Request/Notify, eNB/MME Status Transfer, Paging, Reset, Error Indication, UE Capability Info Indication, Location Reporting Control/Report
- NAS EMM (3GPP TS 24.301): Attach Request/Accept/Complete, Authentication Request/Response, Security Mode Command/Complete, Detach Request/Accept, TAU Request/Accept, Service Request/Reject, Paging
- NAS Security (3GPP TS 33.401): EEA0/EEA1/EEA2 ciphering, EIA0/EIA1/EIA2 integrity protection applied to NAS messages after Security Mode Complete
Note: S1AP uses a simplified TLV encoding (not full ASN.1 PER) and UDP transport (not SCTP) for emulation simplicity. The S6a interface uses a simplified binary protocol (not full Diameter). Protocol semantics and procedures are preserved.
eNodeB MME HSS SGW PGW
| | | | |
|-- S1 Setup ----->| | | |
|<- S1 Setup Rsp --| | | |
| | | | |
|-- Initial UE --->| | | |
| (Attach Req) | | | |
| |-- Auth Info Req ->| | |
| |<- Auth Info Ans --| | |
|<- DL NAS --------| | | |
| (Auth Request) | | | |
|-- UL NAS ------->| | | |
| (Auth Response)| | | |
|<- DL NAS --------| | | |
| (Sec Mode Cmd) | | | |
|-- UL NAS ------->| | | |
| (Sec Mode Cmp) | | | |
| |--- Create Session Req ----------->| |
| | | |-- Create Sess ->|
| | | |<- Create Rsp --|
| |<-- Create Session Rsp ------------| (UE IP alloc) |
|<- Init Ctx Setup-| | | |
| (Attach Accept)| | | |
|-- Init Ctx Rsp ->| | | |
| (eNB S1-U) |--- Modify Bearer Req ----------->| |
| |<-- Modify Bearer Rsp ------------| |
|-- UL NAS ------->| | | |
| (Attach Cmplt) | | | |
| | | | |
|============= USER PLANE ACTIVE (GTP-U: eNB <-> SGW <-> PGW) ========|
Source eNB MME Target eNB SGW
| | | |
|-- HO Required --->| | |
| |-- HO Request --->| |
| |<- HO Req Ack ----| |
|<- HO Command -----| | |
|-- eNB Status Tx ->| | |
| |-- MME Status Tx->| |
| | | |
| [UE moves to target eNB] | |
| | | |
| |<- HO Notify -----| |
| |--- Modify Bearer Req ----------->|
| |<-- Modify Bearer Rsp ------------|
|<- UE Ctx Release -| | |
PGW SGW MME eNodeB
| | | |
|-- Create Bearer Req ----------->| |
| | | |
| |-- Create Bearer Req ---------->|
| | | |
| | |-- E-RAB Setup->|
| | |<- E-RAB Rsp --|
| | | |
| |<- Create Bearer Rsp -----------|
|<- Create Bearer Rsp ------------| |
UL (Uplink): App -> TUN (uesimtun0) -> eNB [GTP-U encap] -> SGW [re-encap] -> PGW [decap] -> TUN (ogstun) -> Internet
DL (Downlink): Internet -> TUN (ogstun) -> PGW [GTP-U encap] -> SGW [re-encap] -> eNB [decap] -> TUN (uesimtun0) -> App
- C compiler (GCC or Clang)
- CMake >= 3.14
- Linux kernel with TUN/TAP support
- Docker and Docker Compose (for containerized deployment)
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)Binaries are output to the build/ directory.
docker-compose build# Start the full EPC without delay simulation
docker-compose up -d
# Start with GEO satellite delay (600ms RTT)
DELAY_MS=300 DELAY_JITTER_MS=15 docker-compose up -d
# Start with LEO satellite delay (40ms RTT)
DELAY_MS=20 DELAY_JITTER_MS=5 docker-compose up -d
# Start with local FTP server for testing
docker-compose --profile local-services up -d
# View logs
docker-compose logs -f
# View logs for a specific component
docker-compose logs -f mme
# Stop
docker-compose downRun each component in a separate terminal (requires root for TUN):
# Terminal 1: HSS
sudo ./build/satcore_hss config/hss.conf
# Terminal 2: PGW
sudo ./build/satcore_pgw config/pgw.conf
# Terminal 3: SGW
sudo ./build/satcore_sgw config/sgw.conf
# Terminal 4: MME
sudo ./build/satcore_mme config/mme.conf
# Terminal 5: eNodeB
sudo ./build/satcore_enb config/enb.confThe delay simulation uses Linux tc/netem on the eNodeB container's network interface to emulate satellite backhaul characteristics.
| Orbit | One-way Delay | RTT | Jitter | Bandwidth | Loss |
|---|---|---|---|---|---|
| GEO (Geostationary) | 300ms | ~600ms | 15ms | 2 Mbit | 0.1% |
| MEO (Medium Earth) | 62ms | ~125ms | 8ms | 10 Mbit | 0.05% |
| LEO (Low Earth) | 20ms | ~40ms | 5ms | 50 Mbit | 0.01% |
| HEO (Highly Elliptical) | 200ms | ~400ms | 30ms | 5 Mbit | 0.2% |
# Apply preset from inside the eNB container
docker exec satcore_enb /scripts/setup_delay.sh --preset geo
docker exec satcore_enb /scripts/setup_delay.sh --preset leo
# Custom delay
docker exec satcore_enb /scripts/setup_delay.sh --delay 300 --jitter 20 --bandwidth 5000
# Check current rules
docker exec satcore_enb /scripts/setup_delay.sh --status
# Clear all delay rules
docker exec satcore_enb /scripts/setup_delay.sh --clearSet these in docker-compose.yml or via command line:
| Variable | Description | Default |
|---|---|---|
DELAY_MS |
One-way delay (ms) | 0 |
DELAY_JITTER_MS |
Jitter (ms) | 0 |
DELAY_CORRELATION |
Jitter correlation (%) | 25 |
DELAY_DISTRIBUTION |
Distribution (normal/pareto/paretonormal) | normal |
BANDWIDTH_LIMIT |
Bandwidth cap (kbit) | 0 (unlimited) |
PACKET_LOSS |
Packet loss (%) | 0 |
Edit config/subscribers.csv:
# IMSI,K,OPc,AMF,APN,QCI
001010000000001,465b5ce8b199b49faa5f0a2ee238a6bc,e8ed289deba952e4283b54e88e6b7610,8000,internet,9Default Docker network layout:
| Network | Subnet | Purpose |
|---|---|---|
epc_net |
10.10.0.0/16 | Internal EPC signaling + user plane |
sgi_net |
10.20.0.0/16 | PGW external (internet/local resources) |
| Container | IP (epc_net) | IP (sgi_net) |
|---|---|---|
| MME | 10.10.0.2 | - |
| SGW | 10.10.0.3 | - |
| PGW | 10.10.0.4 | 10.20.0.4 |
| eNB | 10.10.0.5 | - |
| HSS | 10.10.0.10 | - |
| FTP | - | 10.20.0.100 |
UE IP pool: 10.45.0.0/16 (allocated by PGW)
The PGW routes UE traffic to:
- Internet: Via NAT masquerade on the
sgi_netinterface - Local services: Directly reachable on
sgi_net(e.g., FTP server at 10.20.0.100)
To add local services, add them to docker-compose.yml on the sgi_net network.
satcore/
├── CMakeLists.txt # Build system
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Container orchestration
├── config/ # Configuration files
│ ├── mme.conf / sgw.conf / pgw.conf / hss.conf / enb.conf
│ └── subscribers.csv
├── scripts/
│ ├── setup_delay.sh # tc/netem delay simulation
│ ├── setup_routing.sh # PGW iptables/NAT setup
│ └── entrypoint.sh # Docker entrypoint
├── include/satcore/ # Public headers
│ ├── types.h # Core 3GPP types
│ ├── gtp_v2.h / gtp_u.h # GTP protocol definitions
│ ├── s1ap.h / nas.h # S1AP and NAS definitions
│ ├── log.h / config.h # Utilities
│ ├── network.h / tun.h # Network and TUN interface
└── src/
├── common/ # Shared utilities
├── protocol/ # Protocol encode/decode
├── mme/ # MME implementation
├── sgw/ # SGW implementation
├── pgw/ # PGW implementation
├── hss/ # HSS implementation
└── enb/ # eNodeB emulator
SatCore is a protocol-level emulator for testing and research, not a production EPC. The following 3GPP features are simplified or not implemented:
| Category | What's Missing |
|---|---|
| NAS procedures | Extended Service Request, PDN Connectivity Request, ESM bearer resource management |
| Idle mode | DRX not simulated. Paging, ECM-IDLE/CONNECTED transitions, Service Request, and TAU are supported |
| Authentication | Simplified XOR-based key derivation, not real Milenage (AES-128). No SQN resync. Sufficient for emulation, not for security testing |
| S6a interface | Simplified binary protocol, not Diameter |
| Multiple PDN connections | Single PDN/APN per UE only. No dynamic PDN connectivity |
| IPv6 | UE addresses are IPv4 only. PDN types IPv6/IPv4v6 are defined but not implemented |
| QoS enforcement | QCI and ARP values are carried in signaling but no traffic shaping, policing, or scheduling is applied |
| X2 handover | No X2 interface. S1-based handover is fully supported; Path Switch Request is handled but no direct eNB-to-eNB communication |
| MME pooling / S1-flex | Single MME instance only. No GUMMEI-based load balancing |
| SGi interface | Basic TUN device with host-level NAT. No in-process firewall, connection tracking, DNS, or DHCP relay |
| S1AP procedures | No Write Replace Warning, ENB Configuration Update, or Overload. Reset, Error Indication, Location Reporting, and UE Capability Info Indication are supported |
| GTPv2-C messages | No Release Access Bearers, Downlink Data Notification, Suspend/Resume, Create Indirect Data Forwarding Tunnel, or Update Bearer |
- S1AP encoding: Uses TLV over UDP by default (not ASN.1 APER over SCTP), though an APER codec and SCTP transport are available for real eNB interop
- IP pool: Capped at 4096 concurrent UE addresses
- Handover: Transparent container is passed through without interpretation
- Dedicated bearers: Can be created via GTPv2-C Create Bearer flow, but limited to a single PDN context per UE
See LICENSE file for details.