README
¶
vowifi-go
A from-scratch, community Go implementation of the VoHive VoWiFi runtime boundary. vowifi-go reproduces the public APIs and protocol layers that VoHive consumes for SIM/ISIM AKA, SWu/ePDG tunneling, IMS registration, messaging, voice bridging, emergency calling, and userspace dataplane experiments. The repository is intentionally a library — it owns no main service. VoHive supplies the process boundary; vowifi-go supplies the Go packages that fill it.
Status. vowifi-go is under active development. It is an independent implementation — not affiliated with, endorsed by, or a drop-in replacement for any vendor, operator, or official closed-source VoWiFi product. Full SIP transaction timers, advanced IMS interworking, carrier-specific behaviour, production hardening, and real-world compatibility work are still being implemented incrementally behind the current APIs.
Table of contents
- What this module is
- Status and disclaimer
- Quick start
- Repository layout
- Architecture deep-dive
- Public API surface
- Integration snippet
- Local development and CI
- Module dependencies and the
replacedirective - Coverage of major protocol features
- Known gaps and device-trial requirements
- Security, privacy, and compliance
- Repository rules (developer hygiene)
- Documentation index
- License and contact
What this module is
github.com/Starktomy/vowifi-go is a Go module that VoHive (or any host
process that already manages a modem, SIM slot, and outer IP path) can import to:
- negotiate an SWu/ePDG tunnel with EAP-AKA / EAP-AKA' authentication,
- register and refresh an IMS binding over SIP REGISTER + Digest AKA,
- exchange SMS over IMS
MESSAGE, run USSD over IMSINVITE/INFO, - place and receive MMTel voice calls with SDP / RTP / SRTP media,
- handle E911/TS.43 entitlement and emergency INVITEs with PIDF-LO,
- drive the Linux TUN/XFRM (or userspace) dataplane that carries all of the above in userspace.
The project keeps hardware, modem, network, TUN, routing, and command execution boundaries injectable so the entire test suite runs over loopback without a real SIM, a real TUN device, or root privileges.
For documentation that goes deeper into a single area:
| Topic | Where it lives |
|---|---|
| Implementation inventory | docs/FEATURES.md |
| Architectural overview | docs/ARCHITECTURE.md |
| Local dev and CI workflow | docs/DEVELOPMENT.md |
| VoHive readiness gaps | docs/VOHIVE_READINESS.md |
| Coding-agent guide | AGENTS.md |
Status and disclaimer
This project is still under active development and is not feature-complete. APIs, behaviour, compatibility assumptions, and supported scenarios may change as the implementation evolves.
vowifi-go is a third-party independent open implementation. It is not affiliated with, endorsed by, authorized by, or jointly developed with any mobile network operator, device vendor, chipset vendor, SIM vendor, ePDG provider, IMS provider, or official closed-source VoWiFi implementation.
Users are solely responsible for any compliance, regulatory, contractual,
operational, or financial consequence of using or deploying this software. See
the full notice in docs/DISCLAIMER.md.
Quick start
Run the full unit test suite from the repository root:
go test ./...
Run the same local CI entry point as GitHub Actions:
make ci
Pull the module into a host program:
go get github.com/Starktomy/vowifi-go@latest
Run the manual old-VoHive compatibility check from a local VoHive checkout:
VOHIVE_DIR=/path/to/vohive GO=/usr/local/go/bin/go GOFMT=/usr/local/go/bin/gofmt make compat-vohive
The local CI path is loopback-only — no real modem, no real TUN device, no root.
Repository layout
flowchart LR
subgraph engine["engine/"]
sim["engine/sim<br/>AKA contracts"]
swu["engine/swu<br/>SWu/ePDG + IKEv2 + EAP-AKA + ESP"]
swuikev2["engine/swu/ikev2"]
swuesp["engine/swu/esp"]
swutun["engine/swu (TUN, XFRM, MOBIKE, packet_pump)"]
swueapaka["engine/swu/eapaka"]
end
subgraph runtimehost["runtimehost/"]
types["types.go (Phase, State)"]
registrar["imsregistrar.go"]
diag["diagnostics.go (redacted state)"]
carrier["carrier/"]
e911["e911/"]
messaging["messaging/"]
simauth["simauth/"]
simtransport["simtransport/"]
identity["identity/"]
eventhost["eventhost/"]
voiceclient["voiceclient/"]
voicehost["voicehost/"]
end
subgraph internal["internal/"]
tracefixture["tracefixture/ (redacted fixtures)"]
end
engine --> runtimehost
runtimehost --> internal
voiceclient --> identity
voiceclient --> messaging
voicehost --> voiceclient
simauth --> engine
carrier --> simauth
carrier --> e911
e911 --> swu
The arrows are intended to be read as depends on at import time. They are
not sequence-diagram arrows — see §5 for behavior.
Architecture deep-dive
This section is split into three technical sub-sections plus two diagrams that the rest of the on-ramp nests under. Each subsection names the package and the file path that owns the responsibility.
SIM and AKA bridge
engine/sim is intentionally a tiny contract package. It defines
AKAResult{RES,CK,IK,AUTS}, AKAAuthRequest{Application,RAND,AUTN},
SyncFailureError, MACFailureError, and three interfaces: AKAProvider,
AKAAuthenticator, and ISIMAKAProvider. Real implementations live in
runtimehost/simauth and engine/swu/eapaka:
runtimehost/simauth/aka.gowraps aLogicalChannelTransportand exposesNewAKAProvider,BuildUSIMAuthAPDU,ParseUSIMAuthResponse,ClassifyUSIMAuthResponse,ClassifyUSIMAuthExchange,ParseAUTS.runtimehost/simauth/identity.gocarries the EAP-AKA identity helpers —FormatEAPAKAPermanentIdentity,FormatEAPAKAPrimePermanentIdentity,ParseEAPAKAPermanentIdentity,DecodeUSIMIMSI,EncodeUSIMIMSI,MNCLengthFromAD, plus ISIM identity string encode/decode.runtimehost/simauth/apdu.goandruntimehost/simtransport/at.go,runtimehost/simtransport/recovery.go,runtimehost/simtransport/status.go,runtimehost/simauth/hostauth.go,runtimehost/simauth/qmiuim.gocarry the three hardware-side transport paths (logical-channel APDU, ATCCHO/CGLA, QMI UIM).engine/swu/eapakareuses the AKA response shape (RES/CK/IK/AUTS) to feed EAP-AKA / EAP-AKA' attribute encoding on the IKE_AUTH exchange.
flowchart LR
SIM["SIM card / eUICC"]
AT["AT (CCHO/CGLA/CCHC)"]
APDU["Logical-channel APDU"]
QMI["QMI UIM"]
CRSM["AT+CRSM / CRSM helpers"]
SIM --> AT
SIM --> APDU
SIM --> QMI
APDU --> id["runtimehost/identity.ReadISIMIdentity"]
CRSM --> id
AT --> at["runtimehost/simtransport.NewAdapter"]
QMI --> qmi["runtimehost/simauth/qmiuim"]
id --> aka["runtimehost/simauth.AKAAuthenticator"]
qmi --> aka
at --> aka
aka --> contract["engine/sim.AKAResult"]
contract --> eap["engine/swu/eapaka (EAP-AKA/AKA')"]
SWu/ePDG and IMS crypto plane
engine/swu is the largest single package and is where the wireless-side
cryptography lives. Sub-packages:
engine/swu/ikev2— IKEv2 packet layer. Builds IKE_SA_INIT, IKE_AUTH, CREATE_CHILD_SA, INFORMATIONAL, and MOBIKE UPDATE_SA_ADDRESSES packets; derivesSK_*keys from SKEYSEED; understands proposals / transforms / KE / Nonce / IDi / IDr / AUTH / CP / TS / Notify / Delete / EAP; supports combined-mode AES-GCM proposals. Also routes encrypted INFORMATIONAL/DPD payloads, runs encrypted IKE_AUTH EAP-Identity, and orchestrates full EAP-AKA / EAP-AKA' flows over IKE_AUTH.engine/swu/eapaka— EAP-AKA / EAP-AKA' attribute codec. AT_BIDDING downgrade protection, AT_RAND / AT_AUTN / AT_MAC / AT_RES / AT_AUTS, AT_KDF, AT_CHECKCODE, AT_NOTIFICATION, AT_CLIENT_ERROR, full / pseudonym / reauthentication identity selection.engine/swu/esp— ESP seal/open primitives for userspace dataplane. AES-CBC + HMAC-SHA integrity or combined-mode AES-GCM-16, RFC 4303 padding, anti-replay window.engine/swu/{tun_linux.go, tun_unsupported.go, tun_routing.go, tun_tunnel_manager.go, xfrm.go, packet_pump.go, packet_session.go, udp_esp_transport.go, kernel_session.go}— Linux TUN device plumbing, XFRM/IPsec state install, the userspace packet pump that bridges TUN inner IP to ESP outer UDP, and MOBIKE triggers.engine/swu/{ike_tunnel_manager.go, ike_control.go, ike_liveness.go, eap_reauth.go, mobike_state.go}— top-level tunnel-manager types:swu.NewIKEPacketTunnelManager,swu.NewTUNIKETunnelManager, and theswu.EAPReauthenticationStatehook.- The single entry
engine/swu/swu.goexportsTunnelConfig,ProxyConfig,IMSIdentity,DataplaneMode{Disabled, Userspace, Kernel}, plusTunnelManager,TunnelSession,TunnelResult,MOBIKERequest, andNewTraceID-style helpers.
sequenceDiagram
autonumber
participant UE as vOWiFi-go Instance
participant ePDG as ePDG
participant IMS as IMS Registrar (P-CSCF/S-CSCF)
participant SIM as SIM / AKA
UE->>UE: Start(req StartRequest)
UE->>SIM: IdentityRead (ISIM via simauth.AKAProvider)
SIM-->>UE: Identity, IMPI, IMSI
UE->>ePDG: IKE_SA_INIT (KE, Nonce, NAT-D)
ePDG-->>UE: IKE_SA_INIT (KE, Nonce, NAT-D)
UE->>ePDG: IKE_AUTH IDi (EAP, CHILD_SA, TSi, TSr)
ePDG->>UE: EAP-Request/AKA-Challenge (RAND, AUTN, AT_KDF, ...)
UE->>SIM: AKA Challenge (RAND, AUTN)
SIM-->>UE: AKAResult {RES, CK, IK} (or AUTS on SQN failure)
UE->>ePDG: EAP-Response/AKA-Challenge (AT_RES, AT_MAC)
ePDG-->>UE: IKE_AUTH success + CHILD_SA (ESP SPI, TSi/TSr)
UE->>UE: derive ESP keys, install TUN routes
UE->>IMS: SIP REGISTER (Contact via inner IP)
IMS-->>UE: 401 + WWW-Authenticate (Digest AKA)
UE->>IMS: REGISTER + Authorization (Digest-AKA1)
IMS-->>UE: 200 OK + Service-Route + P-Associated-URI
IMS, voice, messaging, emergency
runtimehost/voiceclient/— the SIP client side. Owns REGISTER headers, WWW-Authenticate parsing, AKA nonce extraction, Digest MD5/MD5-sess/ SHA-256/SHA-512-256 plus AKAv1-MD5 / AKAv2-MD5 authorizers,Security-Clientproposal generation,Security-Serverselection,RegistrationRecoveryActionandRegistrationRecoveryPlanplanning. The interaction with the SIP REGISTER state machine is documented indocs/*. Voice-client sub-functions exported for consumers:ParseWWWAuthenticate,ParseDigestAuthorization,VerifyDigestAuthorization,ExtractAKAChallengeNonce,BuildDigestAuthorization,BuildAKADigestPassword,BuildRegisterHeaders,ParseRegistrationFailureInfo,PlanRegistrationRecovery.runtimehost/voicehost/— the SIP server / dialog side. SIP dialog helpers (OutboundCallAgent,DialogTerminator,DialogCanceller,DialogInfoSender,DialogMessageSender,DialogPrackSender,DialogOptionsSender,DialogReferSender,DialogNotifySender,DialogSubscribeSender,DialogUpdater,DialogReinviter,DialogHoldController,DialogRTPDTMFSender), SDP rewrite, RTP/RTCP relay, DTMF (RFC 2833 / SIP INFO / auto-relay).runtimehost/messaging/— SMS and USSD. IMSMESSAGEtransport hooks, inbound SMS, delivery report matching, CPIM/3GPP SMS/IMDN payload unpacking, SMS segmentation (SegmentSMS,SegmentSMSWithOptions), SMS PDU assembly, UCS2/GSM-7/NLI handling, USSD XML and dialog transports. The package exportsNewService,SMSTransport,USSDTransport,DeliveryStore,IMSMessagingRetryStore,IMSMessagingRetryDueStore,IMSMessagingRetryReplayResult,SendOptions,SendOutcome,RPCauseText.runtimehost/e911/— TS.43-style entitlement bootstrap, JSON/XML emergency address parsing, HTTP Digest AKA retry for entitlement challenges, PIDF-LO (multipart/relatedbody +cid:Geolocation), emergency service URN mapping. ExposesNewDefaultHTTPClient, an injectableHTTPClientinterface,HTTPRequest/HTTPResponse.runtimehost/carrier/— per-carrierCarrierPolicy, P-CSCF profile selection, IMS realm selection, VoWiFi blocked-MCC classification, and AT&T TS.43/E911 presets. ExposesLoadCarrierOverrides,ClearCarrierOverrides,ResolveEffectiveCarrierConfig,NormalizeSubscriberProfile,IMSAccessProfileForSubscriber,CarrierPolicyForSubscriber,CarrierPolicyForConfig,PlanIMSRegistration,IsVoWiFiBlockedMCC,DefaultIMSRealm,DefaultPrivateIdentityRealm,DefaultNAIRealm.runtimehost/eventhost/— internal pub-sub. ExposesDispatcher,RuntimeStateSnapshot,SMSReceived,SMSSent,USSDUpdated,LocalNumberLearned,LogNotify.runtimehost/diagnostics.go— redacted snapshot projections:SafeDiagnosticState,SafeDiagnosticIMSRegistrationResult,SafeDiagnosticIMSRegistrationRecoveryState,SafeDiagnosticIMSRegisterResponseDecision,SafeDiagnosticString,SafeDiagnosticError. Every VoHive-facing diagnostic shape is built through these helpers.runtimehost/types.go— top-level lifecycle types:Phase{Starting, SIMReady, Ready, Stopped, Error},State,Event,Observer,ObserverFunc,Modem,APDUAccess,IdentityReader,CRSMAccess,ModemAccess,SIMAdapter,SessionConfig,IMSRegistrationConfig,IMSRegistrationResult,IMSRegistrationRecoveryState,IMSRegistrar,StartRequest, and theInstancereturned fromStart(ctx, req).
stateDiagram-v2
[*] --> Idle
Idle --> ContactSent: build REGISTER
ContactSent --> DigestChallenge: 401/407 + WWW-Authenticate
DigestChallenge --> AKAChallenge: AKA nonce in Digest
AKAChallenge --> Authenticated: 200 OK + Service-Route
Authenticated --> Refreshing: T_expire reached
Refreshing --> Authenticated: 200 OK
Authenticated --> Recovering: 408/503/5xx + Retry-After
Recovering --> Authenticated: re-REGISTER 200 OK
Authenticated --> MinExpiresRetry: 423 Min-Expires
MinExpiresRetry --> Authenticated: re-REGISTER with new Expires
Authenticated --> DeRegistering: shutdown
DeRegistering --> Stopped: 200 OK (Expires: 0)
Recovering --> Stopped: give up
Voice, messaging, emergency dispatch
flowchart LR
subgraph wire["VoWiFi-go Instance (runtimehost)"]
In["Instance.StartOutboundCall / EndVoiceCall / SendDialog*"]
Outbound["voicehost.IMSOutboundAgent"]
Inbound["voicehost.IMSInboundAgent"]
Voice["voicehost.RTPRelay"]
end
subgraph messaging["messaging"]
SMS["Instance.SendSMSWithOptions / HandleIncomingSMS"]
USSD["Instance.SendDialogInfo / HandleIMSInfo/Bye"]
CPIM["messaging.SMS / USSD segmentation"]
end
subgraph e911r["e911"]
EPlan["e911.Plan / profile selection"]
EBootstrap["TS.43 entitlement bootstrap"]
EPIDF["PIDF-LO / emergency INVITE"]
end
subgraph Recovery
RState["runtimehost.diagnostics (redacted)"]
end
In --> Outbound
Inbound --> Voice
SMS --> CPIM
USSD --> CPIM
EPlan --> EBootstrap --> EPIDF
Outbound --> Recovery
Voice --> Recovery
CPIM --> Recovery
EPIDF --> Recovery
Public API surface
| Concern | Entry point(s) | File |
|---|---|---|
| Lifecycle | runtimehost.Start, (*Instance).Stop, (*Instance).State, (*Instance).DiagnosticState, (*Instance).Status, (*Instance).Obs, runtimehost.NewTraceID, runtimehost.WithTraceID, runtimehost.SetLogger |
runtimehost/types.go, runtimehost/diagnostics.go |
| IMS registration | runtimehost.IMSRegistrar, IMSRegisterTransportFactory, IMSVoiceTransportFactory, IMSSMSTransportFactory, IMSUSSDTransportFactory |
runtimehost/imsregistrar.go |
| SIP header / Digest / Sec-Agree | voiceclient.ParseWWWAuthenticate, voiceclient.ParseDigestAuthorization, voiceclient.VerifyDigestAuthorization, voiceclient.ExtractAKAChallengeNonce, voiceclient.BuildDigestAuthorization, voiceclient.BuildAKADigestPassword, voiceclient.BuildRegisterHeaders, voiceclient.ParseRegistrationFailureInfo, voiceclient.PlanRegistrationRecovery, voiceclient.IMSProfile, voiceclient.SIPRegisterTransport |
runtimehost/voiceclient/voiceclient.go |
| Voice dialogs | voicehost.Agent, voicehost.OutboundCallAgent, voicehost.DialogTerminator*, voicehost.DialogInfoSender, voicehost.DialogMessageSender, voicehost.DialogPrackSender, voicehost.DialogOptionsSender, voicehost.DialogReferSender, voicehost.DialogNotifySender, voicehost.DialogSubscribeSender, voicehost.DialogUpdater, voicehost.DialogReinviter, voicehost.DialogHoldController, voicehost.DialogRTPDTMFSender |
runtimehost/voicehost/voicehost.go |
| SMS / USSD | messaging.NewService, messaging.SegmentSMS, messaging.SegmentSMSWithOptions, messaging.SMSTransport, messaging.USSDTransport, messaging.DeliveryStore, messaging.IMSMessagingRetryStore, messaging.IMSMessagingRetryDueStore, messaging.RPCauseText, messaging.WithSuppressSendTGSuccess, messaging.SendOptions, messaging.SendOutcome, messaging.IncomingSMS, messaging.SMSDeliveryReport |
runtimehost/messaging/messaging.go |
| E911 / TS.43 | e911.NewDefaultHTTPClient, e911.HTTPClient, e911.HTTPRequest, e911.HTTPResponse |
runtimehost/e911/e911.go |
| Carrier presets | carrier.LoadCarrierOverrides, carrier.ClearCarrierOverrides, carrier.ResolveEffectiveCarrierConfig, carrier.NormalizeSubscriberProfile, carrier.IMSAccessProfileForSubscriber, carrier.CarrierPolicyForSubscriber, carrier.CarrierPolicyForConfig, carrier.PlanIMSRegistration, carrier.IsVoWiFiBlockedMCC, carrier.DefaultIMSRealm, carrier.DefaultPrivateIdentityRealm, carrier.DefaultNAIRealm, carrier.SubscriberProfile, carrier.CarrierPolicy, carrier.IMSRegistrationPlan |
runtimehost/carrier/carrier.go |
| SIM / AKA contracts | sim.AKAResult, sim.AKAAuthRequest, sim.SyncFailureError, sim.MACFailureError, sim.AKAProvider, sim.AKAAuthenticator, sim.ISIMAKAProvider, sim.AKAApplication |
engine/sim/sim.go |
| SIM / AKA implementations | simauth.NewAKAProvider, simauth.BuildUSIMAuthAPDU, simauth.ParseUSIMAuthResponse, simauth.ClassifyUSIMAuthResponse, simauth.ClassifyUSIMAuthExchange, simauth.ParseAUTS, simauth.FormatEAPAKAPermanentIdentity, simauth.FormatEAPAKAPrimePermanentIdentity, simauth.ParseEAPAKAPermanentIdentity, simauth.DecodeUSIMIMSI, simauth.EncodeUSIMIMSI, simauth.MNCLengthFromAD, simauth.DecodeISIMIdentityString, simauth.EncodeISIMIdentityString, simauth.PadISIMIdentityRecord |
runtimehost/simauth/{aka.go, identity.go} |
| SWu / ePDG | swu.TunnelManager, swu.NewIKEPacketTunnelManager, swu.NewTUNIKETunnelManager, swu.MOBIKERequest, swu.EAPReauthenticationState, swu.EPDGRouteExclusion, swu.TUNRoute, swu.TUNRule, swu.DataplaneMode{Disabled,Userspace,Kernel} |
engine/swu/{swu.go, ike_tunnel_manager.go, tun_tunnel_manager.go, mobike_state.go, ...} |
| IKEv2 packet layer | engine/swu/ikev2 (build-only IKEv2 packet codec plus full IKE_SA_INIT / IKE_AUTH / CREATE_CHILD_SA / INFORMATIONAL / MOBIKE exchange runners) |
engine/swu/ikev2/*.go |
| ESP seal/open | engine/swu/esp (AES-CBC + HMAC-SHA, AES-GCM-16, anti-replay) |
engine/swu/esp/esp.go |
| Dataplane | swu.XFRM, swu.TUNDeviceConfig, swu.TUNTunnelManagerConfig, swu.PacketPump, swu.UDPESPTransport, swu.MOBIKEState |
engine/swu/{xfrm.go, tun_*.go, packet_pump.go, udp_esp_transport.go, ...} |
| Identity | identity.Identity, identity.Profile, identity.PreparedSession, identity.ReadISIMIdentity, identity.ReadISIMIdentityCRSM, identity.ExtractIMEI, identity.AKAAppPreference* |
runtimehost/identity/{identity.go, recovery.go} |
| Event host | eventhost.Dispatcher, eventhost.RuntimeStateSnapshot, eventhost.SMSReceived, eventhost.SMSSent, eventhost.USSDUpdated, eventhost.LocalNumberLearned, eventhost.LogNotify |
runtimehost/eventhost/eventhost.go |
| Trace fixtures (re-importer only) | tracefixture.NewRedactor, tracefixture.RedactString, tracefixture.RedactBytes, tracefixture.RedactSIPString, tracefixture.RedactLines, tracefixture.Transcript, tracefixture.ParseTranscriptJSON, tracefixture.ParseAndRedactTranscriptJSON, tracefixture.ValidateTranscript, tracefixture.RedactTranscript, tracefixture.ValidateTranscriptRedaction |
internal/tracefixture/{redactor.go, transcript.go} |
Only exported symbols that have already shipped in the current commit are listed. New entry points that surface during incremental implementation will be added here on the next README pass.
Integration snippet
This is a wire-format level sketch — it shows how a host program feeds the runtime with a SIM AKA provider and a SIP register transport, and then watches the lifecycle state. VoHive wraps this with its own bootstrap; new hosts can copy the shape.
ctx := context.Background()
// 1. SIM identity + AKA provider (real modem, test stub, or QMI UIM).
aka := simauth.NewAKAProvider(logicalChannelTransport)
simAdapter := runtimehost.NewReaderSIMAdapter(aka)
modemAccess := runtimehost.NewModemAccessAdapterWithRecovery(modem, runtimehost.SIMAccessRecoveryOptions{
AllowVendorSpecific: true,
})
// 2. Carrier-derived policy.
policy, err := carrier.PlanIMSRegistration(carrier.IMSRegistrationPlanInput{
IMSI: imsi,
MCC: mcc,
MNC: mnc,
})
if err != nil { /* fall back to default policy or block */ }
// 3. IMS registrar built locally or supplied by VoHive.
registrar := runtimehost.IMSRegistrar(myIMSCtor)
// 4. Dataplane mode — `swu.DataplaneModeUserspace` is the loopback-friendly
// default; `swu.DataplaneModeKernel` requires root or CAP_NET_ADMIN.
inst, err := runtimehost.Start(ctx, runtimehost.StartRequest{
DeviceID: deviceID,
Profile: identity.Profile{IMSI: imsi, MCC: mcc, MNC: mnc},
Prepared: preparedSession,
Dataplane: runtimehost.DataplanePolicy{Mode: swu.DataplaneModeUserspace},
SIM: simAdapter,
Access: modemAccess,
IMSRegistrar: registrar,
NetworkMode: "LTE",
VoiceUserAgent: "vowifi-go/0.1",
})
if err != nil { return err }
defer inst.Stop(context.Background())
// 5. Observe lifecycle.
inst.AddObserver(runtimehost.ObserverFunc(func(ctx context.Context, ev runtimehost.Event) {
switch ev.State.Phase {
case runtimehost.PhaseReady:
// voice, SMS, USSD transports now exist; begin using them.
case runtimehost.PhaseError:
// ev.State.LastReason carries a redacted string.
}
}))
// 6. Drive work later.
out, err := inst.SendSMSWithOptions(ctx, "+15555550100", "hi", messaging.SendOptions{})
_ = out; _ = err
The above deliberately uses only symbols documented in §6 Public API surface.
Local development and CI
Local commands
make help # list all targets
make ci # default CI (version + module path + hygiene + tidy + vet + smoke + test)
make go-version
make module-path
make hygiene-check
make privacy-check
make download
make fmt-check
make tidy-check
make vet
make smoke
make test
make race # opt-in
make coverage # opt-in
make compat-vohive # against a local VoHive checkout
make compat-vohive-selftest
If go / gofmt is not on PATH, pass the absolute path:
GO=/usr/local/go/bin/go GOFMT=/usr/local/go/bin/gofmt make ci
GitHub Actions
.github/workflows/ci.yml runs Ubuntu against both the minimum Go patch
required by go.mod and the latest patch in that minor line, calling
make ci so local validation matches the default CI job. The workflow can
also be started manually with optional race and coverage inputs that mirror
make race / make coverage.
The manual .github/workflows/vohive-compat.yml workflow checks this module
against an older VoHive consumer checkout. The script clones or copies the
VoHive checkout into a temporary directory, first verifies this checkout still
declares github.com/Starktomy/vowifi-go and does not use the legacy module
path in Go module / source files, rewrites legacy vowifi-go module
references to github.com/Starktomy/vowifi-go when needed, verifies no legacy
module references remain, confirms only the temporary VoHive module resolves
github.com/Starktomy/vowifi-go through a replace pointing at this
repository, then runs the focused VoHive test set. The source VoHive checkout
is not modified.
Override VOHIVE_COMPAT_PACKAGES, VOHIVE_COMPAT_RUN,
VOHIVE_COMPAT_BUILD_PACKAGES, VOHIVE_COMPAT_TMPDIR, VOWIFI_MODULE, or
VOWIFI_COMPAT_LEGACY_BASE to broaden coverage as needed.
Module dependencies and the replace directive
go.mod pins:
github.com/Starktomy/vowifi-go— this module (the canonical name).github.com/emiago/sipgo— SIP client/server transport foundation.github.com/google/uuid— UUID generation for trace IDs.github.com/icholy/digest— Digest challenge / authorization helpers.github.com/Starktomy/swu-go— SWu protocol layer; substituted viareplace github.com/Starktomy/swu-go => ../swu-gofor local development. The local../swu-godirectory is expected to exist. Because of thereplace,go.sumintentionally omits theswu-gochecksum line — Go's checksum resolution skips modules resolved throughreplace.github.com/strongswan/govici— strongSwan vici client used in the SWu supervisor bridge.gvisor.dev/gvisor— used in userspace TUN tests.github.com/songgao/water,github.com/vishvananda/netns,github.com/Starktomy/netlink,golang.org/x/sys,golang.org/x/sync,golang.org/x/time, and several indirect packages.
CI runs the module-path guard on every commit to catch any drift in
module github.com/.../... declarations.
Coverage of major protocol features
Each row names a protocol area, the public surface that owns it, and the spec
it targets. For long-form inventory, see docs/FEATURES.md.
| Protocol area | Owning package(s) | Spec target |
|---|---|---|
| SIM AKA (USIM / ISIM) | engine/sim, runtimehost/simauth, engine/swu/eapaka |
3GPP TS 33.102, TS 31.102 |
| SIM APDU / AT / QMI UIM | runtimehost/simtransport, runtimehost/simauth |
ETSI TS 102 221, 3GPP TS 27.005 / 27.007, Qualcomm QMI |
| IKEv2 / EAP-AKA / EAP-AKA' | engine/swu/ikev2, engine/swu/eapaka |
RFC 7296, RFC 5448, RFC 4186 / RFC 4187 |
| ESP / userspace dataplane | engine/swu/esp, engine/swu/{tun_*, xfrm, packet_pump} |
RFC 4303, RFC 3948 (NAT-T) |
| IMS REGISTER / Digest / AKA | runtimehost/voiceclient, runtimehost/imsregistrar, runtimehost/e911 |
RFC 3261, RFC 8760 (AKA'), TS 33.203 |
| Security-Verify / Sec-Agree | runtimehost/voiceclient |
3GPP TS 33.203 |
| SMS over IMS / USSD | runtimehost/messaging |
RFC 3428, RFC 4975, RFC 4976, 3GPP TS 24.011 / 24.341 |
| Voice (SIP / SDP / RTP / SRTP) | runtimehost/voicehost |
RFC 3261 / 3264 / 3550 / 3551 / 3711, 3GPP TS 26.114 |
| E911 / TS.43 | runtimehost/e911 |
AT&T TS.43, NENA i3, RFC 6442 / RFC 8145 / RFC 7859 (Geopriv / PIDF-LO) |
| Diagnostic redaction | runtimehost/diagnostics, internal/tracefixture |
project policy, GDPR-aware logging |
| VoHive compatibility harness | scripts/compat-vohive.sh, .github/workflows/vohive-compat.yml |
wire-level integration test |
Known gaps and device-trial requirements
The project explicitly does not claim full parity with the official
closed-source VoWiFi implementation. The current gaps that block production
use are listed in docs/VOHIVE_READINESS.md
across four readiness levels:
- Compile-compatible.
- Loopback-functional.
- Device-functional.
- Production-ready.
Concretely, current open work that is not yet proven on real devices is
highlighted in that document under the readiness matrix and the P0 list. The
README does not duplicate the matrix — read docs/VOHIVE_READINESS.md for
the canonical gap inventory.
Security, privacy, and compliance
The repository enforces a privacy guard on tracked worktree content through
scripts/ci.sh and make hygiene-check / make privacy-check. Forbidden
content includes personal email addresses, local home paths, legacy module
references, and vowifi-go identifiers that should now read
github.com/Starktomy/vowifi-go.
Git author and committer metadata are intentional and preserved. The
AGENTS.mdpolicy explicitly forbids rewrites of.gitauthor / committer metadata as part of privacy cleanup. Adjust the local Git identity throughgit config user.name/user.emailif it is wrong, but never rewrite existing commit history.
Every diagnostic shape that crosses the VoHive boundary is funneled through
runtimehost/diagnostics.go's Safe* helpers, which strip the kinds of
material that are unsafe to leak in operator-facing logs (subscriber IDs,
keys, nonces, raw APDU bodies, internal IP / MAC addresses, local paths).
Read the full notice in docs/DISCLAIMER.md.
Repository rules (developer hygiene)
AGENTS.md is the standing guide for AI coding agents and human contributors
working in this repository. It pins:
- Keep public APIs stable unless a breaking change is explicitly approved.
- Prefer real protocol behaviour over mock-only surface compatibility.
- Inject hardware, modem, network, TUN, route, and command boundaries so CI remains loopback-friendly.
- Treat operator-specific behaviour as explicit compatibility work — no carrier flow should be assumed complete without tests or real-device evidence.
- Validate with
make cibefore committing meaningful changes and runmake compat-vohive-selftest(and the manualvohive-compat.ymlworkflow) when changing public runtime behaviour. - Push after committing when the user explicitly asks.
- Never revert unrelated local changes.
Documentation index
| Document | Purpose |
|---|---|
README.md |
This document — integrated on-ramp. |
README.zh-CN.md |
Chinese mirror of this README. |
docs/ARCHITECTURE.md |
Package map, runtime boundaries, high-level flow. |
docs/FEATURES.md |
Detailed implementation inventory and known gaps. |
docs/DEVELOPMENT.md |
Local and CI workflow, VoHive compatibility check. |
docs/VOHIVE_READINESS.md |
Readiness levels, gap matrix, P0 list. |
docs/DISCLAIMER.md |
English disclaimer. |
docs/DISCLAIMER.zh-CN.md |
Chinese disclaimer. |
AGENTS.md |
Coding-agent guide, developer-hygiene rules, Git-identity rules. |
Makefile |
All Make targets. |
License and contact
See docs/DISCLAIMER.md for licensing, warranty, and
liability terms. Issues, questions, or coordination requests should be
opened on the project's public issue tracker; maintainer contact information
is listed in the repository's profile.