ss7client

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

ss7-3eai-gateway-client

Go client and NATS wire contract for ss7-3eai-gateway, an SS7 signalling gateway (M3UA / SCCP / TCAP / MAP) that applications drive over NATS.

Licensed under the Apache License 2.0, separately from the gateway (AGPL-3.0-only), so an SMSC or any other application can link it under any licence.

go get github.com/3eAI-Labs/ss7-3eai-gateway-client

What it covers

The interfaces the gateway implements end to end — the MAP short-message path, subscriber location and state, call routing, USSD, and location management, authentication and purging with the gateway as HLR:

Operation Method Subjects
SendRoutingInfoForSM (MAP op 45) SendRoutingInfoForSM map.sri.request → map.sri.response
MT-ForwardSM (MAP op 44) MTForwardSM map.mt.sms.request → map.mt.sms.response
MO-ForwardSM (MAP op 46), received from a foreign MSC SubscribeMO map.mo.sms
AnyTimeInterrogation (MAP op 71), towards the HLR AnyTimeInterrogation map.ati.request → map.ati.response
ProvideSubscriberInfo (MAP op 70), towards the VLR ProvideSubscriberInfo map.psi.request → map.psi.response
SendRoutingInfo (MAP op 22), towards the HLR, as GMSC — gateway 0.7.6 and later SendRoutingInfo map.routing.request → map.routing.response
USSD sessions (MAP ops 59, 60, 61), as gsmSCF — gateway 0.7.7 and later SubscribeUSSD, StartUSSD, USSDRequest, USSDNotify, USSDRelease, USSDReject events on map.ussd.event.<route>; map.ussd.start / map.ussd.command → map.ussd.response
Location updates (MAP ops 2 and 7), as HLR: the application decides — gateway 0.7.8 and later ServeLocationUpdates map.ul (NATS requests, gateway → application)
CancelLocation (MAP op 3), towards a VLR — gateway 0.7.8 and later CancelLocation map.cl.request → map.cl.response
ProvideRoamingNumber (MAP op 4), towards a VLR — gateway 0.7.8 and later ProvideRoamingNumber map.prn.request → map.prn.response
InsertSubscriberData (MAP op 7) alone, towards a VLR — gateway 0.7.8 and later InsertSubscriberData map.isd.request → map.isd.response
SendAuthenticationInfo (MAP op 56), as HLR: the application is the AuC — gateway 0.7.9 and later ServeAuthentication map.sai (NATS requests, gateway → application)
PurgeMS (MAP op 67), as HLR — gateway 0.7.9 and later ServePurges map.purge (NATS requests, gateway → application)

The package also defines the Message JSON schema, parameter keys, status values and the gateway's failure codes — the contract for consumers in other languages.

Usage

nc, err := nats.Connect(natsURL)
if err != nil { /* ... */ }
defer nc.Close()

gw, err := ss7client.New(nc)
if err != nil { /* ... */ }
defer gw.Close()

sri, err := gw.SendRoutingInfoForSM(ctx, ss7client.SRIRequest{
	MSISDN:               "905321112233",
	ServiceCentreAddress: ss7client.E164("905001112233"),
})
if err != nil { /* *ss7client.GatewayError, ErrInvalidRequest, or a context error */ }

_, err = gw.MTForwardSM(ctx, ss7client.MTRequest{
	IMSI:                 sri.IMSI,
	NetworkNodeNumber:    ss7client.E164(sri.NetworkNodeNumber),
	ServiceCentreAddress: ss7client.E164("905001112233"),
	TPDU:                 smsDeliverTPDU, // 3GPP TS 23.040, opaque to the gateway
})

sub, err := gw.SubscribeMO("smsc", func(m *ss7client.Message) {
	// m.Sender: originating MSC, m.Recipient: SMSC address, m.PayloadData: SMS-SUBMIT TPDU
})

loc, err := gw.AnyTimeInterrogation(ctx, ss7client.ATIRequest{
	MSISDN:    "905321112233",
	Requested: ss7client.RequestedInfo{Location: true, State: true},
})
// loc.Info.Location.CellGlobalID, loc.Info.Location.VLRNumber, loc.Info.State.State, …

route, err := gw.SendRoutingInfo(ctx, ss7client.RoutingRequest{MSISDN: "905321112233"})
// route.Routing.RoamingNumber.Digits (MSRN), route.Routing.Forwarding, route.Routing.VMSCAddress, route.IMSI

// USSD: a menu for whoever dials a code routed to "balance" (map.ussd_routes).
gw.SubscribeUSSD("balance", "balance-app", func(e *ss7client.USSDEvent) {
	if e.Action != ss7client.USSDBegin {
		return // an end: e.Status and e.Detail say how the session ended
	}
	go func() { // never wait for a human on the subscription's goroutine
		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
		defer cancel()
		a, err := gw.USSDRequest(ctx, e.SessionID, ss7client.USSDText{Text: "1 Balance\n2 Offers"})
		if err != nil {
			// The session may still be open: end it, on a fresh context.
			_ = gw.USSDReject(context.Background(), e.SessionID, ss7client.MAPErrSystemFailure)
			return
		}
		_ = gw.USSDRelease(ctx, e.SessionID, &ss7client.USSDText{Text: "You chose " + a.Reply.Text})
	}()
})

// Location updates: the application is the HLR's location management.
gw.ServeLocationUpdates("hlr", func(ctx context.Context, t *ss7client.LocationUpdateTurn) ss7client.LocationUpdateAnswer {
	switch t.Action {
	case ss7client.ULUpdateLocation: // a VLR registers t.IMSI
		profile, ok := subscribers.Lookup(ctx, t.IMSI)
		if !ok {
			return ss7client.LocationUpdateAnswer{Reject: ss7client.MAPErrUnknownSubscriber}
		}
		return ss7client.LocationUpdateAnswer{Insert: profile} // *ss7client.SubscriberData
	case ss7client.ULInsertResult: // t.Insert says what the VLR did not take, t.Status a failure
		if t.Status != "" {
			return ss7client.LocationUpdateAnswer{Reject: ss7client.MAPErrSystemFailure}
		}
		subscribers.Register(ctx, t.IMSI, t.Update.VLRNumber, t.Update.MSCNumber)
		return ss7client.LocationUpdateAnswer{Accept: true}
	}
	return ss7client.LocationUpdateAnswer{} // ULEnd: t.Status says how it ended
})

Behaviour worth knowing

  • Correlation. Responses are broadcast on the response subject; every client instance receives every response and keeps only those carrying its own correlation IDs.

  • Failures. Every outcome comes back on the response subject as *GatewayError:

    • the peer answered with a MAP ReturnError → Status REMOTE_ERROR, Code the MAP error code (MAPErrAbsentSubscriberSM, MAPErrUnknownSubscriber, …), Message its name — the input to an SMSC's retry decision;
    • a TCAP Reject → REMOTE_ERROR with ErrCodeRemoteError;
    • the dialogue timed out or was aborted → TIMEOUT / ABORTED with a negative Code;
    • the gateway refused the request before starting a dialogue → REJECTED with ErrCodeRejected and the reason (gateway 0.7.4 and later).

    Any status the client does not recognise is treated as a failure, never as success.

  • Deadlines. Gateways before 0.7.4 send no response for a request they reject before starting a dialogue, and no gateway can answer a request that is not valid JSON. The client checks the fields the gateway requires before publishing, and bounds a request without a context deadline by DefaultTimeout (40s, longer than the gateway's default 30s TCAP dialogue timeout).

  • Access. AnyTimeInterrogation, ProvideSubscriberInfo and SendRoutingInfo return the IMSI, serving node or location of any subscriber they are asked about; USSD puts text on any handset and reads what subscribers type.

    • Grant publish rights only to the applications that need them:

      • map.ati.request, map.psi.request, map.routing.request;

      • map.ussd.start (text on any handset, unasked);

      • map.ussd.command (acts on any live session whose ID it holds).

      • map.cl.request, map.prn.request, map.isd.request (cancel any subscriber's registration, take a roaming number to route their calls, change their profile in a VLR).

      The call routing subjects are outside map.sri.*, so granting SRI-for-SM does not grant them. A grant of map.*.request or map.> does.

    • Response and event subjects are broadcast. Subscribe rights show every answer, from every requester:

      • map.ati.response, map.psi.response and map.routing.response carry IMSIs, locations and roaming numbers;
      • map.ussd.response carries what subscribers type, PINs included;
      • map.ussd.event.<route> carries who dialled what.

      Grant each USSD route only to the application that serves it.

    • Whoever subscribes to map.ul answers location updates: it is the HLR. Grant it to the HLR application alone, with permission to publish its replies (NATS allow_responses); the gateway needs to subscribe to its reply inboxes (_INBOX.>). Grant publish on map.ul to the gateway alone: anyone who can publish there can send a forged turn and read the profile the HLR application answers with. map.ul and map.isd.response carry subscriber profiles, IMEISVs and the VLRs subscribers are in.

    • map.sai carries authentication vectors: key material (Kc, CK, IK, KASME). Grant subscribe to the AuC alone and publish to the gateway alone, as for map.ul, and run NATS with TLS. Grant publish on map.purge to the gateway alone: a forged purge makes a subscriber unreachable.

    • WithDecodeErrorHandler receives raw payloads, USSD text included.

    • A Client subscribes to an operation's response subject on its first request of that operation, so an account limited to some operations works.

  • MO delivery is a plain NATS publish: an MO-ForwardSM published while no subscriber is connected is lost. Use a queue group to share the stream across instances.

Licence

Apache License 2.0. Copyright 2026 3eAI Labs Ltd. Contributions are accepted under the 3eAI Labs Contributor Licence Agreement; see CONTRIBUTING.md.

Documentation

Overview

Package ss7client is the NATS client for ss7-3eai-gateway: the subjects, the message schema and a typed request/response client for the MAP interfaces the gateway implements.

This module is licensed under the Apache License 2.0, separately from the gateway server (AGPL-3.0-only), so an SMSC or any other application can link it without taking on the server's licence. The dependency runs one way: the server imports this module for the wire contract, this module never imports the server.

Interface covered

Only the interface the gateway implements end to end is exposed:

Wire model

Every message is a JSON-encoded Message. Requests are published on a request subject; the gateway queue-subscribes, runs the MAP dialogue and publishes the outcome — result or failure — on the matching response subject with the request's correlation_id. Response subjects are broadcast: every client instance receives every response and keeps only its own, by correlation_id. A Client subscribes to a response subject on the first request that needs it.

Location updates, authentication and purging are the exception: the gateway asks and the application answers, as NATS request and reply.

A request the gateway refuses before starting a dialogue — a missing or invalid field, no capacity for a new dialogue — is answered with StatusRejected from gateway 0.7.4 on; earlier gateways send nothing, and nothing can be sent for a request that is not valid JSON. Client therefore validates the fields the gateway requires before publishing, and applies a default deadline when the context has none.

Index

Constants

View Source
const (
	// SubjectAuthentication carries sendAuthenticationInfo requests,
	// gateway → application, as NATS requests (queue group recommended).
	SubjectAuthentication = "map.sai"
	// SubjectPurge carries purgeMS requests, gateway → application, as
	// NATS requests.
	SubjectPurge = "map.purge"
)

Authentication and MS purging with the gateway in the HLR's role (3GPP TS 29.002 §8.5.2, §8.1.6). Needs gateway 0.7.9 or later.

  • A VLR or SGSN asks for authentication vectors with sendAuthenticationInfo. The application is the AuC: it computes the vectors, the gateway carries them — see ServeAuthentication.
  • A VLR or SGSN tells the HLR it deleted a subscriber's record with purgeMS: the HLR marks the subscriber purged, so that calls and short messages to it are treated as to an absent subscriber — see ServePurges.

Both are NATS requests, gateway → application, answered with a reply.

The vectors carry key material (Kc, CK, IK, KASME): run NATS with TLS, and allow only the gateway to publish on SubjectAuthentication and only the AuC to subscribe to it.

View Source
const (
	NodeVLR           = "vlr"
	NodeSGSN          = "sgsn"
	NodeSCSCF         = "s-cscf"
	NodeBSF           = "bsf"
	NodeGANAAAServer  = "gan-aaa-server"
	NodeWLANAAAServer = "wlan-aaa-server"
	NodeMME           = "mme"
	NodeMMESGSN       = "mme-sgsn"
)

Values of Authentication.RequestingNodeType (TS 29.002 RequestingNodeType). Empty: the request did not say; the field comes after the extension marker, so an older VLR or SGSN leaves it out.

View Source
const (
	// SubjectATIRequest carries AnyTimeInterrogation requests, application → gateway.
	SubjectATIRequest = "map.ati.request"
	// SubjectATIResponse carries AnyTimeInterrogation results and failures, gateway → application.
	SubjectATIResponse = "map.ati.response"
	// SubjectPSIRequest carries ProvideSubscriberInfo requests, application → gateway.
	SubjectPSIRequest = "map.psi.request"
	// SubjectPSIResponse carries ProvideSubscriberInfo results and failures, gateway → application.
	SubjectPSIResponse = "map.psi.response"
)

NATS subjects of the MAP location interface (3GPP TS 29.002 §8.11).

View Source
const (
	DomainCS = "cs"
	DomainPS = "ps"
)

Domains of RequestedInfo.Domain (TS 29.002 DomainType).

View Source
const (
	// SubjectSRIRequest carries SRI-for-SM requests, application → gateway.
	SubjectSRIRequest = "map.sri.request"
	// SubjectSRIResponse carries SRI-for-SM results and failures, gateway → application.
	SubjectSRIResponse = "map.sri.response"
	// SubjectMTSMSRequest carries MT-Forward-SM requests, application → gateway.
	SubjectMTSMSRequest = "map.mt.sms.request"
	// SubjectMTSMSResponse carries MT-Forward-SM results and failures, gateway → application.
	SubjectMTSMSResponse = "map.mt.sms.response"
	// SubjectMOSMS carries MO-Forward-SM received from a foreign MSC, gateway → application.
	SubjectMOSMS = "map.mo.sms"
)

NATS subjects of the MAP SMS interface. The gateway queue-subscribes to the request subjects (queue group = its cluster name) and publishes on the response subjects.

View Source
const (
	// ParamServiceCentreAddress (request, SRI and MT): the SMSC address, as
	// a digit string or an [AddressString] object.
	ParamServiceCentreAddress = "service_centre_address"
	// ParamNetworkNodeNumber (request, MT): the serving MSC/VLR address
	// returned by SRI-for-SM, as a digit string or an [AddressString] object.
	ParamNetworkNodeNumber = "network_node_number"
	// ParamTPDUBase64 (request, MT): the TPDU as standard base64, an
	// alternative to Message.PayloadData.
	ParamTPDUBase64 = "tpdu_base64"
	// ParamVMSCAddress (response, SRI): digits of the network node number
	// returned by the HLR.
	ParamVMSCAddress = "vmsc_address"
)

Keys of Message.Parameters understood or produced by the gateway.

View Source
const (
	// StatusDelivered: MT-Forward-SM ended with a ReturnResult. A successful
	// SRI-for-SM, AnyTimeInterrogation, ProvideSubscriberInfo or
	// SendRoutingInfo response carries an empty status.
	StatusDelivered = "DELIVERED"
	// StatusTimeout: the gateway's TCAP dialogue timer expired.
	StatusTimeout = "TIMEOUT"
	// StatusAborted: the peer aborted the dialogue (TC-P-ABORT / TC-U-ABORT).
	StatusAborted = "ABORTED"
	// StatusRejected: the gateway refused the request before starting a
	// dialogue — a missing or invalid field, or no capacity for a new
	// dialogue. ErrorCode is ErrCodeRejected and ErrorMessage the reason.
	StatusRejected = "REJECTED"
	// StatusRemoteError: the peer answered with a MAP ReturnError — ErrorCode
	// is the MAP error code (positive, see MAPErr*) and ErrorMessage its name —
	// or with a TCAP Reject / a ReturnError without a code — ErrorCode is
	// ErrCodeRemoteError.
	StatusRemoteError = "REMOTE_ERROR"
)

Values of Message.Status on response subjects.

View Source
const (
	ErrCodeTimeout      int32 = -1
	ErrCodeAborted      int32 = -2
	ErrCodeRemoteError  int32 = -3
	ErrCodeRejected     int32 = -4
	ErrCodeUnclassified int32 = -99
)

Gateway-private failure codes in Message.ErrorCode. They are negative so they never collide with MAP error codes (3GPP TS 29.002 MAP-ErrorCodes, positive).

View Source
const (
	MAPErrUnknownSubscriber         int32 = 1
	MAPErrUnidentifiedSubscriber    int32 = 5
	MAPErrAbsentSubscriberSM        int32 = 6
	MAPErrIllegalSubscriber         int32 = 9
	MAPErrTeleserviceNotProvisioned int32 = 11
	MAPErrIllegalEquipment          int32 = 12
	MAPErrCallBarred                int32 = 13
	MAPErrFacilityNotSupported      int32 = 21
	MAPErrSubscriberBusyForMTSMS    int32 = 31
	MAPErrSMDeliveryFailure         int32 = 32
	MAPErrSystemFailure             int32 = 34
	MAPErrDataMissing               int32 = 35
	MAPErrUnexpectedDataValue       int32 = 36
)

MAP error codes (3GPP TS 29.002, MAP-ErrorCodes) that SendRoutingInfoForSM and MT-ForwardSM can return, carried in Message.ErrorCode with StatusRemoteError. The gateway passes any code through; these are the ones an SMSC's retry logic normally distinguishes.

View Source
const (
	// unknownSubscriber's diagnostic, which it may go without. TS 29.002
	// names gprs-eps-subscription-unknown for a sendAuthenticationInfo from
	// an SGSN for a subscriber without GPRS (figure 25.5/6).
	CauseIMSIUnknown                = "imsi-unknown"
	CauseGPRSEPSSubscriptionUnknown = "gprs-eps-subscription-unknown"
	// roamingNotAllowed's cause, which it always carries: without one,
	// plmn-roaming-not-allowed (TS 29.002 §8.1.2.3).
	CausePLMNRoamingNotAllowed       = "plmn-roaming-not-allowed"
	CauseOperatorDeterminedBarring   = "operator-determined-barring"
	CauseSupportedRATTypesNotAllowed = "supported-rat-types-not-allowed"
)

Causes that qualify an error the application refuses a request with (TS 29.002 §7.6.1, MAP-ER-DataTypes): RejectCause in an answer, ErrorCause on the wire.

View Source
const (
	// SubjectLocationUpdate carries the turns of location updates,
	// gateway → application, as NATS requests: the application answers
	// each with a reply (queue group recommended).
	SubjectLocationUpdate = "map.ul"
	// SubjectCancelLocationRequest carries CancelLocation requests,
	// application → gateway.
	SubjectCancelLocationRequest = "map.cl.request"
	// SubjectCancelLocationResponse carries their results and failures.
	SubjectCancelLocationResponse = "map.cl.response"
	// SubjectPRNRequest carries ProvideRoamingNumber requests.
	SubjectPRNRequest = "map.prn.request"
	// SubjectPRNResponse carries their results and failures.
	SubjectPRNResponse = "map.prn.response"
	// SubjectISDRequest carries stand-alone InsertSubscriberData requests.
	SubjectISDRequest = "map.isd.request"
	// SubjectISDResponse carries their results and failures.
	SubjectISDResponse = "map.isd.response"
)

Location management with the gateway in the HLR's role (3GPP TS 29.002 §8.1, §8.8.1, §10.2), for an application that is the HLR's location management (TS 23.012): it holds the subscribers and decides, the gateway speaks MAP to the VLRs. Needs gateway 0.7.8 or later.

  • Location updates: a VLR registers a subscriber with updateLocation. The gateway asks the application what to do, one turn at a time, as the MAP process in the HLR does (TS 29.002 figure 19.1.1/13) — see ServeLocationUpdates.
  • CancelLocation tells a VLR to forget a subscriber (it moved to another VLR, or the subscription was withdrawn).
  • ProvideRoamingNumber asks the VLR serving a subscriber for a roaming number (MSRN) to route a call on.
  • InsertSubscriberData sends changed subscriber data to the VLR serving a subscriber.

The three requests go to the VLR named by its number (ParamVLRNumber's digits, as for ProvideSubscriberInfo) as global title with SSN 7, or to DPC when given; the gateway answers from SSN 6, so sccp.local_subsystems must include it.

View Source
const (
	MAPErrRoamingNotAllowed        int32 = 8
	MAPErrNoRoamingNumberAvailable int32 = 39
)

MAP error codes of the mobility operations not defined before. updateLocation is answered with MAPErrSystemFailure, MAPErrDataMissing, MAPErrUnexpectedDataValue, MAPErrUnknownSubscriber or MAPErrRoamingNotAllowed. A VLR answers cancelLocation with MAPErrDataMissing or MAPErrUnexpectedDataValue; insertSubscriberData with those or MAPErrUnidentifiedSubscriber; provideRoamingNumber with MAPErrSystemFailure, MAPErrDataMissing, MAPErrUnexpectedDataValue, MAPErrFacilityNotSupported, MAPErrORNotAllowed, MAPErrAbsentSubscriber or MAPErrNoRoamingNumberAvailable.

View Source
const (
	// Turns, gateway → application.
	ULUpdateLocation = "update_location" // the VLR's updateLocation: what to do?
	ULInsertResult   = "insert_result"   // what became of the subscriber data sent
	ULEnd            = "end"             // the location update ended without the application's answer
	// Answers, application → gateway.
	ULInsert = "insert" // send this subscriber data (insertSubscriberData)
	ULAccept = "accept" // the location update succeeded: updateLocation's result
	ULReject = "reject" // it failed: updateLocation's error Error
)

Values of LocationUpdate.Action.

View Source
const (
	CancellationUpdateProcedure      = "updateProcedure"
	CancellationSubscriptionWithdraw = "subscriptionWithdraw"
)

CancellationType values of CancelLocation.

View Source
const (
	// SubjectRoutingRequest carries SendRoutingInfo requests, application → gateway.
	SubjectRoutingRequest = "map.routing.request"
	// SubjectRoutingResponse carries SendRoutingInfo results and failures, gateway → application.
	SubjectRoutingResponse = "map.routing.response"
)

NATS subjects of MAP call routing (3GPP TS 29.002 §10.1, SendRoutingInfo). They are not under map.sri.*, the SRI-for-SM subjects, so that NATS permissions can grant one without the other: SendRoutingInfo returns the IMSI and the serving MSC of any subscriber it is asked about.

View Source
const (
	MAPErrBearerServiceNotProvisioned int32 = 10
	MAPErrForwardingViolation         int32 = 14
	MAPErrCUGReject                   int32 = 15
	// MAPErrAbsentSubscriber is a call's absentSubscriber, not the
	// short-message MAPErrAbsentSubscriberSM (6).
	MAPErrAbsentSubscriber int32 = 27
	MAPErrNumberChanged    int32 = 44
	// MAPErrBusySubscriber is a call's busySubscriber, not the
	// short-message MAPErrSubscriberBusyForMTSMS (31).
	MAPErrBusySubscriber    int32 = 45
	MAPErrNoSubscriberReply int32 = 46
	MAPErrORNotAllowed      int32 = 48
)

MAP error codes (TS 29.002 MAP-ErrorCodes) that SendRoutingInfo can return in addition to those with constants already: unknownSubscriber, teleserviceNotProvisioned, callBarred, facilityNotSupported, systemFailure, dataMissing, unexpectedDataValue. Error parameters (the absent subscriber's reason, the call barring cause) are not passed on.

View Source
const (
	// SubjectUSSDEventPrefix is the prefix of the event subjects, one per
	// route: map.ussd.event.<route>.
	SubjectUSSDEventPrefix = "map.ussd.event."
	// SubjectUSSDStart carries network-initiated session starts,
	// application → gateway (queue group).
	SubjectUSSDStart = "map.ussd.start"
	// SubjectUSSDCommand carries commands on an existing session,
	// application → every gateway node.
	SubjectUSSDCommand = "map.ussd.command"
	// SubjectUSSDResponse carries the answers to starts and commands,
	// gateway → application.
	SubjectUSSDResponse = "map.ussd.response"

	// USSDDefaultRoute receives the subscriber-initiated sessions no
	// configured route matches (map.ussd_routes), and the network-initiated
	// ones started without a route.
	USSDDefaultRoute = "default"
)
  • Endings
  • Routing and sessions

USSD (3GPP TS 29.002 §11.9, TS 23.090), with the gateway as gsmSCF under networkUnstructuredSsContext-v2. Needs gateway 0.7.7 or later.

A USSD exchange is a session: one TCAP dialogue that stays open while the subscriber reads and answers. A session starts in one of two ways:

  • The subscriber starts it (dials *123#): the HLR opens a dialogue with processUnstructuredSS-Request, and the gateway publishes a "begin" event on the route the dialed string matches (SubscribeUSSD). The application answers with USSDRequest (a prompt; returns the reply) and USSDNotify (text the handset displays), and ends it with USSDRelease and the final text — or USSDReject and a MAP error.
  • The application starts it (network-initiated): StartUSSD sends unstructuredSS-Request or unstructuredSS-Notify to the subscriber's HLR; the session continues the same way and ends with USSDRelease (no final text: a last message is a USSDNotify before it).

Endings

Every session ends exactly once, and the gateway publishes one "end" event for it on its route, whoever ended it. Core NATS delivers at most once: an event (or answer) lost on the way is not sent again, so keep a timeout of your own for every session. A reply the gateway cannot publish ends its session (StatusAborted). The endings:

Status          Code                   meaning
""              0                      released: Detail says by whom
                                       ("application" or "network")
StatusTimeout   ErrCodeTimeout         map.ussd_session_timeout passed, or
                                       the network did not answer in time
StatusAborted   ErrCodeAborted         the dialogue was aborted (the
                                       subscriber cancelled, a node failed)
StatusRemoteError a MAP error code     the network refused a request or
                                       notify (absentSubscriber, ussd-Busy…)

A command that fails because the session ended returns the same status as a *GatewayError, and the end event is published as well: the error is the caller's view of the ending, the event everyone's.

Routing and sessions

A session lives on the gateway node that holds its dialogue. Commands go to every node on SubjectUSSDCommand; the node that holds the session acts, the others ignore the command. The holding node answers a command it cannot carry out with StatusRejected: an unknown or ended session, a request or notify while another is outstanding, USSDRelease without the final text of a subscriber-initiated session (or with one for a network-initiated session), USSDReject on a network-initiated session. USSDRelease and USSDReject are carried out with a request or notify outstanding: that one fails with StatusAborted. Only if that node is gone does a command go unanswered, and the caller's deadline applies.

A session waits for one thing at a time — the subscriber's answer to the request or notify outstanding, else the application's next command — and for at most map.ussd_session_timeout each time (the operations' timer ml, TS 29.002 §17.1.2: 1 to 10 minutes).

Session IDs are opaque strings of at most 64 characters, unguessable; do not parse them.

View Source
const (
	// Events.
	USSDBegin = "begin" // a subscriber started a session; USSD carries what they sent
	USSDEnd   = "end"   // the session is over (see Endings)

	// Commands.
	USSDRequest = "request" // show text and collect the subscriber's reply
	USSDNotify  = "notify"  // show text; the handset confirms receipt
	USSDRelease = "release" // end the session; with the final text of a subscriber-initiated one
	USSDReject  = "reject"  // end a subscriber-initiated session with USSD.Error
)

Values of USSD.Action.

View Source
const (
	DCSGSM7 byte = 0x0F // GSM 7 bit default alphabet, language unspecified
	DCSUCS2 byte = 0x48 // general data coding, uncompressed, no class, UCS2
)

Data coding schemes the gateway uses when it encodes Text (TS 23.038 §5).

View Source
const (
	MAPErrUnknownAlphabet int32 = 71
	MAPErrUSSDBusy        int32 = 72
)

MAP error codes of the USSD operations (TS 29.002 MAP-ErrorCodes) not already defined. USSDReject answers with one of systemFailure, dataMissing, unexpectedDataValue, unknownAlphabet and callBarred; the network answers a request or notify with these and absentSubscriber, illegalSubscriber, illegalEquipment, ussd-Busy.

View Source
const DefaultTimeout = 40 * time.Second

DefaultTimeout bounds a request whose context has no deadline. It is longer than the gateway's default TCAP dialogue timeout (tcap.dialogue_timeout, 30s), so the gateway's own TIMEOUT response normally arrives first.

View Source
const DefaultUSSDTimeout = 3*time.Minute + 10*time.Second

DefaultUSSDTimeout bounds a USSD call whose context has no deadline. A human is reading and typing; the gateway's own session timeout (map.ussd_session_timeout, 180 s by default) ends the session regardless.

View Source
const MAPErrATINotAllowed int32 = 49

MAPErrATINotAllowed is ati-NotAllowed (TS 29.002 MAP-ErrorCodes): the HLR does not accept AnyTimeInterrogation from this gsmSCF-Address. The other errors of ATI and PSI — systemFailure, dataMissing, unexpectedDataValue, unknownSubscriber — have MAPErr* constants already.

View Source
const MaxUSSDOctets = 160

MaxUSSDOctets is maxUSSD-StringLength (TS 29.002): at most 182 GSM 7-bit characters (two for each of the extension table's: €, [, ], …) or 80 UCS2 characters.

View Source
const (
	// ParamVLRNumber (request, PSI): the address of the VLR serving the
	// subscriber, as a digit string or an [AddressString] object.
	ParamVLRNumber = "vlr_number"
)

Keys of Message.Parameters for the location interface.

Variables

View Source
var (
	// ErrInvalidRequest wraps a request rejected before publishing because
	// a field the gateway requires is missing.
	ErrInvalidRequest = errors.New("ss7 client: invalid request")
	// ErrClosed is returned for requests made after, or pending at, Close.
	ErrClosed = errors.New("ss7 client: closed")
)

Functions

func AccessRestrictionNames added in v0.5.0

func AccessRestrictionNames() []string

func CAMEL4CSINames added in v0.5.0

func CAMEL4CSINames() []string

func CLIRestrictionNames added in v0.5.0

func CLIRestrictionNames() []string

The ENUMERATED names, by value.

func NetworkAccessModeNames added in v0.5.0

func NetworkAccessModeNames() []string

func ODBGeneralNames added in v0.5.0

func ODBGeneralNames() []string

The named-bit names of the BIT STRINGs above, in bit order: a name's index is its bit (TS 29.002 ASN.1). The gateway maps by them.

func ODBHPLMNNames added in v0.5.0

func ODBHPLMNNames() []string

func OverrideCategoryNames added in v0.5.0

func OverrideCategoryNames() []string

func RATTypeNames added in v0.5.0

func RATTypeNames() []string

func RegionalSubscriptionResponseNames added in v0.5.0

func RegionalSubscriptionResponseNames() []string

func SubscriberStatusNames added in v0.5.0

func SubscriberStatusNames() []string

Types

type ATIRequest added in v0.2.0

type ATIRequest struct {
	// Exactly one of MSISDN and IMSI (digits) identifies the subscriber.
	MSISDN string
	IMSI   string
	// Requested selects what to ask for.
	Requested RequestedInfo
	// HLRGlobalTitle and HLRPointCode address the HLR directly. Without
	// them the gateway routes on the MSISDN as global title (or uses
	// map.hlr_gt / map.hlr_pc when map.sri_routing is "hlr"); a request by
	// IMSI therefore needs one of them or map.sri_routing "hlr".
	HLRGlobalTitle string
	HLRPointCode   uint32
}

ATIRequest is a MAP AnyTimeInterrogation towards the subscriber's HLR (3GPP TS 29.002 §8.11.1).

type AddressString

type AddressString struct {
	Digits        string `json:"digits"`
	Nature        uint8  `json:"nature"`
	NumberingPlan uint8  `json:"numbering_plan"`
}

AddressString is the object form of an address parameter. Nature and NumberingPlan are the TS 29.002 AddressString nature-of-address and numbering-plan indicators, coded as there: Nature 1 = international, 2 = national significant, 4 = subscriber number (not the SCCP global title coding, where international is 4); NumberingPlan 1 = ISDN/E.164. A bare digit string in Parameters means international / ISDN-E.164.

func E164

func E164(digits string) AddressString

E164 returns an international ISDN/E.164 AddressString.

type Authentication added in v0.6.0

type Authentication struct {
	DialogueID string `json:"dialogue_id,omitempty"`
	// AnswerBy (request): the gateway refuses the request with
	// systemFailure when the answer has not come by then.
	AnswerBy *time.Time `json:"answer_by,omitempty"`

	// The request (TS 29.002 §8.5.2.3).
	RequestedVectors           int    `json:"requested_vectors,omitempty"`
	RequestingNodeType         string `json:"requesting_node_type,omitempty"`
	RequestingPLMNID           string `json:"requesting_plmn_id,omitempty"` // 3 octets
	ImmediateResponsePreferred bool   `json:"immediate_response_preferred,omitempty"`
	SegmentationProhibited     bool   `json:"segmentation_prohibited,omitempty"`
	// Resynchronisation: the UE found the sequence number out of range
	// (TS 33.102 §6.3.5).
	Resynchronisation          *Resynchronisation `json:"resynchronisation,omitempty"`
	AdditionalVectors          int                `json:"additional_vectors,omitempty"`
	AdditionalVectorsAreForEPS bool               `json:"additional_vectors_are_for_eps,omitempty"`
	UEUsageTypeRequested       bool               `json:"ue_usage_type_requested,omitempty"`
	// CallingGT: the calling party's global title digits.
	CallingGT string `json:"calling_gt,omitempty"`

	// The answer: vectors, or Error.
	Triplets    []AuthenticationTriplet    `json:"triplets,omitempty"`
	Quintuplets []AuthenticationQuintuplet `json:"quintuplets,omitempty"`
	EPSVectors  []EPSVector                `json:"eps_vectors,omitempty"`
	UEUsageType string                     `json:"ue_usage_type,omitempty"` // 4 octets
	Error       int32                      `json:"error,omitempty"`
	ErrorCause  string                     `json:"error_cause,omitempty"` // a Cause* qualifying Error
	Detail      string                     `json:"detail,omitempty"`
}

Authentication is a sendAuthenticationInfo's part of a Message on SubjectAuthentication: the request, or the application's answer to it. Octet strings are hex.

func (*Authentication) VectorLimits added in v0.6.0

func (r *Authentication) VectorLimits() (setList, eps int)

VectorLimits are how many vectors of each kind an answer to r may carry (TS 29.002 §8.5.2.1, §8.5.2.3): an MME gets EPS vectors only, the number it asked for; a combined MME/SGSN gets the number it asked for of the kind for immediate use and AdditionalVectors of the other kind — EPS when AdditionalVectorsAreForEPS, else triplets or quintuplets; any other node, or a request without a node type, gets triplets or quintuplets only.

type AuthenticationAnswer added in v0.6.0

type AuthenticationAnswer struct {
	Triplets    []AuthenticationTriplet
	Quintuplets []AuthenticationQuintuplet
	EPSVectors  []EPSVector
	// UEUsageType: only when Request.UEUsageTypeRequested.
	UEUsageType string
	// Reject refuses the request with one of sendAuthenticationInfo's
	// errors: MAPErrSystemFailure, MAPErrDataMissing,
	// MAPErrUnexpectedDataValue or MAPErrUnknownSubscriber.
	Reject int32
	// RejectCause qualifies a MAPErrUnknownSubscriber: CauseIMSIUnknown,
	// or CauseGPRSEPSSubscriptionUnknown when an SGSN asks for a subscriber
	// without GPRS. Optional.
	RejectCause string
}

AuthenticationAnswer is the application's answer: vectors, or Reject. Triplets for a GSM subscriber, quintuplets for a UMTS one (never both), EPS vectors for an MME; no more of each kind than Request.VectorLimits allows. No vectors and no Reject is the empty response: the HLR has none to give (TS 29.002 §8.5.2.1).

type AuthenticationQuintuplet added in v0.6.0

type AuthenticationQuintuplet struct {
	RAND string `json:"rand"`
	XRES string `json:"xres"`
	CK   string `json:"ck"`
	IK   string `json:"ik"`
	AUTN string `json:"autn"`
}

AuthenticationQuintuplet is a UMTS vector: RAND 16 octets, XRES 4..16, CK, IK and AUTN 16.

type AuthenticationRequest added in v0.6.0

type AuthenticationRequest struct {
	DialogueID string
	IMSI       string
	Request    *Authentication
	NodeID     string
	Raw        *Message
}

AuthenticationRequest is a sendAuthenticationInfo as the handler gets it.

type AuthenticationTriplet added in v0.6.0

type AuthenticationTriplet struct {
	RAND string `json:"rand"`
	SRES string `json:"sres"`
	Kc   string `json:"kc"`
}

AuthenticationTriplet is a GSM vector: RAND 16 octets, SRES 4, Kc 8.

type BasicService added in v0.3.0

type BasicService struct {
	// Kind is the alternative's ASN.1 name: "ext-BearerService" or
	// "ext-Teleservice".
	Kind string `json:"kind"`
	// Code is the service code (TS 29.002 Ext-BearerServiceCode /
	// Ext-TeleserviceCode, e.g. 11 for telephony), hex.
	Code string `json:"code"`
}

BasicService is TS 29.002 Ext-BasicServiceCode.

type CAMELRouting added in v0.3.0

type CAMELRouting struct {
	Forwarding *ForwardingData `json:"forwarding,omitempty"`
	// SubscriptionInfo is the BER encoding of GmscCamelSubscriptionInfo
	// (T-CSI, O-CSI, D-CSI and their criteria), hex, tag included.
	SubscriptionInfo string `json:"subscription_info"`
}

CAMELRouting is TS 29.002 CamelRoutingInfo.

type CallBarringFeature added in v0.5.0

type CallBarringFeature struct {
	BasicService *BasicService `json:"basic_service,omitempty"`
	Status       SSStatus      `json:"status"`
}

CallBarringFeature is TS 29.002 Ext-CallBarringFeature.

type CallBarringInfo added in v0.5.0

type CallBarringInfo struct {
	SSCode   string               `json:"ss_code"`
	Features []CallBarringFeature `json:"features"`
}

CallBarringInfo is TS 29.002 Ext-CallBarInfo (SSCode, hex: 92 baoc, 93 boic, 94 boic-exHC, 9a baic, 9b bic-roam).

type CancelLocation added in v0.5.0

type CancelLocation struct {
	LMSI string `json:"lmsi,omitempty"` // hex, 4 octets: the identity becomes imsi-WithLMSI
	// Type is the cancellationType, CancellationUpdateProcedure or
	// CancellationSubscriptionWithdraw; empty leaves it out.
	Type string `json:"type,omitempty"`
}

CancelLocation is CancelLocation's part of a request Message.

type CancelLocationRequest added in v0.5.0

type CancelLocationRequest struct {
	IMSI      string // required
	VLRNumber string // required: the VLR's number, E.164 digits
	// VLRPointCode routes on DPC/SSN instead of the VLR number as GT.
	VLRPointCode uint32
	LMSI         string // hex, 4 octets
	Type         string // CancellationUpdateProcedure, CancellationSubscriptionWithdraw or ""
}

CancelLocationRequest is a cancelLocation to a VLR (TS 29.002 §8.1.3).

type CellGlobalID added in v0.2.0

type CellGlobalID struct {
	MCC string `json:"mcc"`
	MNC string `json:"mnc"`
	LAC uint16 `json:"lac"`
	CI  uint16 `json:"ci"`
}

CellGlobalID is a cell global identity or service area identity (TS 23.003).

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client sends MAP requests to the gateway and matches the responses by correlation ID. It is safe for concurrent use. It does not own the NATS connection: Close releases the client's subscriptions only.

func New

func New(nc *nats.Conn, opts ...Option) (*Client, error)

New returns a Client. It subscribes to an operation's response subject on the first request of that operation, not before, so that an application whose NATS account may use only some operations — the SMS subjects but not call routing, say — does not trip a permission violation on the others.

func (*Client) AnyTimeInterrogation added in v0.2.0

func (c *Client) AnyTimeInterrogation(ctx context.Context, req ATIRequest) (*SubscriberInfoResult, error)

AnyTimeInterrogation asks the subscriber's HLR for the information in req.Requested. The gsmSCF-Address the HLR screens the request on is the gateway's own (map.gsmscf_address, else its cluster GT, else its GT); a request cannot choose it, so a NATS publisher cannot present itself as another gsmSCF. On a gateway-reported failure it returns *GatewayError — with MAPErrATINotAllowed when the HLR refuses this gsmSCF.

func (*Client) CancelLocation added in v0.5.0

func (c *Client) CancelLocation(ctx context.Context, req CancelLocationRequest) error

CancelLocation tells a VLR to delete a subscriber, under locationCancellationContext-v3. A nil error is the VLR's result.

func (*Client) Close

func (c *Client) Close() error

Close unsubscribes and fails every pending request with ErrClosed.

func (*Client) InsertSubscriberData added in v0.5.0

func (c *Client) InsertSubscriberData(ctx context.Context, req ISDRequest) (*ISDResult, error)

InsertSubscriberData sends subscriber data to a VLR, under subscriberDataMngtContext-v3. The data must fit one message: the gateway refuses (StatusRejected) what does not, and it can be sent in several requests.

func (*Client) MTForwardSM

func (c *Client) MTForwardSM(ctx context.Context, req MTRequest) (*MTResult, error)

MTForwardSM delivers a short message to the serving MSC. On a gateway-reported failure it returns *GatewayError.

func (*Client) ProvideRoamingNumber added in v0.5.0

func (c *Client) ProvideRoamingNumber(ctx context.Context, req PRNRequest) (*PRNResult, error)

ProvideRoamingNumber asks a VLR for a roaming number (MSRN), under roamingNumberEnquiryContext-v3.

func (*Client) ProvideSubscriberInfo added in v0.2.0

func (c *Client) ProvideSubscriberInfo(ctx context.Context, req PSIRequest) (*SubscriberInfoResult, error)

ProvideSubscriberInfo asks the VLR serving the subscriber for the information in req.Requested. On a gateway-reported failure it returns *GatewayError.

func (*Client) SendRoutingInfo added in v0.3.0

func (c *Client) SendRoutingInfo(ctx context.Context, req RoutingRequest) (*RoutingResult, error)

SendRoutingInfo asks the subscriber's HLR how to route a basic call to req.MSISDN (interrogationType basicCall). The GMSC address the request carries is the gateway's own (its cluster GT, else its GT). It needs a gateway that serves map.routing.request (0.7.6 and later); an older one leaves the request unanswered until the deadline. On a gateway-reported failure it returns *GatewayError — MAPErrAbsentSubscriber, MAPErrBusySubscriber, MAPErrCallBarred and the like when the HLR refuses the call.

func (*Client) SendRoutingInfoForSM

func (c *Client) SendRoutingInfoForSM(ctx context.Context, req SRIRequest) (*SRIResult, error)

SendRoutingInfoForSM asks the subscriber's HLR where to deliver a short message. On a gateway-reported failure it returns *GatewayError.

func (*Client) ServeAuthentication added in v0.6.0

func (c *Client) ServeAuthentication(queue string, handle func(ctx context.Context, r *AuthenticationRequest) AuthenticationAnswer) (*nats.Subscription, error)

ServeAuthentication makes the application the AuC behind the gateway's HLR (TS 29.002 §8.5.2): each sendAuthenticationInfo a VLR or SGSN sends is a request to handle, whose answer goes back as the result or error.

The gateway divides vectors that do not fit one message into several results, as TS 29.002 Annex C recommends for this operation, unless the request has SegmentationProhibited: then it sends as many as fit one message and drops the rest. A request with Resynchronisation asks the AuC to re-synchronise the sequence number before computing vectors.

handle runs on its own goroutine with a context ending at AnswerBy. An answer that breaks the rules above is sent as MAPErrSystemFailure, and the error reported to WithDecodeErrorHandler. With queue non-empty the subscription is in that queue group, so instances of the application share the requests.

func (*Client) ServeLocationUpdates added in v0.5.0

func (c *Client) ServeLocationUpdates(queue string, handle func(ctx context.Context, t *LocationUpdateTurn) LocationUpdateAnswer) (*nats.Subscription, error)

ServeLocationUpdates makes the application the HLR's location management for location updates (TS 29.002 §19.1.1.5).

A VLR's updateLocation is a turn ULUpdateLocation. The handler answers it: Insert subscriber data, Accept, or Reject. After an insert the next turn is ULInsertResult — what the VLR did not take, or the failure — and the handler answers again: more data, Accept or Reject.

A location update ends in one of two ways. Either the gateway carries out the application's Accept or Reject — updateLocation's result or error goes to the VLR — and that is all; or it gets exactly one ULEnd turn, whose answer is not used. A ULEnd comes when:

  • the VLR or the network ends it (an abort, the VLR's silence, a timeout, the gateway shutting down): StatusAborted, StatusTimeout;
  • the gateway refuses it with systemFailure on its own account — the answer did not come by AnswerBy (StatusTimeout), did not parse, or is not one it can carry out (StatusRejected);
  • the result or error could not be sent (StatusAborted).

A ULEnd always comes after the turn being answered, if any: a ULEnd that follows an answer means that answer was not carried out (undo what it committed, such as a registration).

Each turn runs handle on its own goroutine with a context ending at AnswerBy; turns of one location update come one at a time. With queue non-empty the subscription is in that queue group, so instances of the application share the location updates — a later turn may reach another instance, so keep the state of a location update in what DialogueID names, not in memory.

func (*Client) ServePurges added in v0.6.0

func (c *Client) ServePurges(queue string, handle func(ctx context.Context, r *PurgeRequest) PurgeAnswer) (*nats.Subscription, error)

ServePurges makes the application the HLR's subscriber records for purgeMS (TS 29.002 §8.1.6, §19.1.4): mark the subscriber purged, so that routing information for calls and short messages to it reports it absent, and answer what the sender is to freeze.

handle runs on its own goroutine with a context ending at AnswerBy. When no answer comes in time, or one breaks the rules (purgeMS has no systemFailure), the gateway aborts the dialogue and the sender retries later. With queue non-empty the subscription is in that queue group.

func (*Client) StartUSSD added in v0.4.0

func (c *Client) StartUSSD(ctx context.Context, req USSDStart) (*USSDAnswer, error)

StartUSSD starts a network-initiated session: unstructuredSS-Request (answered with the subscriber's reply) or, with Notify, unstructuredSS-Notify (answered when the handset has displayed it), to the subscriber's HLR. The session stays open: continue it with USSDRequest or USSDNotify, end it with USSDRelease.

func (*Client) SubscribeMO

func (c *Client) SubscribeMO(queue string, handle func(*Message)) (*nats.Subscription, error)

SubscribeMO delivers MO-Forward-SM messages the gateway received from foreign MSCs: Sender is the originating MSC address, Recipient the SMSC address, IMSI the originator when the network supplied it, PayloadData the SMS-SUBMIT TPDU. With a non-empty queue, instances sharing the queue name split the stream; with an empty queue every instance receives every message. The returned subscription is the caller's to unsubscribe.

MO is a plain NATS publish: a message published while no subscriber is connected is lost.

func (*Client) SubscribeUSSD added in v0.4.0

func (c *Client) SubscribeUSSD(route, queue string, handle func(*USSDEvent)) (*nats.Subscription, error)

SubscribeUSSD delivers the begins and ends of a route's sessions (map.ussd.event.<route>; USSDDefaultRoute for sessions no configured route matches). Use a queue group: each event then goes to one member of it, and the member that sees a begin need not be the one that sees its end — keep session state where every member can reach it, by session ID. An empty queue gives every subscriber every event, which also lets two instances answer the same session.

handle runs on the subscription's single goroutine: it must not wait for a subscriber's answer — run each session in a goroutine of its own. A begin is delivered even when what the subscriber sent cannot be read: with Message nil, or with Message.Text empty and Detail saying why (the DCS names an alphabet the gateway does not decode — 8-bit data, compressed — leaves Text empty without a Detail). Reject what you cannot serve (MAPErrUnexpectedDataValue, MAPErrUnknownAlphabet).

func (*Client) USSDNotify added in v0.4.0

func (c *Client) USSDNotify(ctx context.Context, sessionID string, t USSDText) (*USSDAnswer, error)

USSDNotify shows text to the subscriber of a session and returns once the handset has displayed it.

func (*Client) USSDReject added in v0.4.0

func (c *Client) USSDReject(ctx context.Context, sessionID string, mapError int32) error

USSDReject ends a session the subscriber started with a MAP error instead of a final text: MAPErrSystemFailure, MAPErrDataMissing, MAPErrUnexpectedDataValue, MAPErrUnknownAlphabet or MAPErrCallBarred.

func (*Client) USSDRelease added in v0.4.0

func (c *Client) USSDRelease(ctx context.Context, sessionID string, final *USSDText) error

USSDRelease ends a session. A session the subscriber started needs the final text they are shown (processUnstructuredSS-Request's result); for a network-initiated one final must be nil.

func (*Client) USSDRequest added in v0.4.0

func (c *Client) USSDRequest(ctx context.Context, sessionID string, t USSDText) (*USSDAnswer, error)

USSDRequest shows text to the subscriber of a session and returns their reply.

type Direction

type Direction string

Direction is relative to the SS7 network: Inbound goes into it (application → gateway), Outbound comes out of it (gateway → application).

const (
	DirectionInbound  Direction = "INBOUND"
	DirectionOutbound Direction = "OUTBOUND"
)

type EPSVector added in v0.6.0

type EPSVector struct {
	RAND  string `json:"rand"`
	XRES  string `json:"xres"`
	AUTN  string `json:"autn"`
	KASME string `json:"kasme"`
}

EPSVector is an EPS vector (EPC-AV): RAND 16 octets, XRES 4..16, AUTN 16, KASME 32.

type ForwardingData added in v0.3.0

type ForwardingData struct {
	// ForwardedToNumber is the forwarded-to number (forwardedToNumber, or
	// longForwardedToNumber when the HLR sent the long form). With CAMEL
	// phase 2 an HLR may send a number that is not E.164: Nature and
	// NumberingPlan say how to read it, and non-digit TBCD values come
	// through as '*', '#', 'a', 'b', 'c'.
	ForwardedToNumber *AddressString `json:"forwarded_to_number,omitempty"`
	// ForwardedToSubaddress is the ISDN subaddress, hex.
	ForwardedToSubaddress string `json:"forwarded_to_subaddress,omitempty"`
	// Options are the ForwardingOptions, when present.
	Options *ForwardingOptions `json:"options,omitempty"`
}

ForwardingData is TS 29.002 ForwardingData.

type ForwardingFeature added in v0.5.0

type ForwardingFeature struct {
	BasicService *BasicService `json:"basic_service,omitempty"`
	Status       SSStatus      `json:"status"`
	// ForwardedToNumber goes as longForwardedToNumber when it is longer
	// than an ISDN-AddressString holds; send that only to a VLR whose
	// capability says LongFTNSupported.
	ForwardedToNumber     *AddressString     `json:"forwarded_to_number,omitempty"`
	ForwardedToSubaddress string             `json:"forwarded_to_subaddress,omitempty"` // hex
	Options               *ForwardingOptions `json:"options,omitempty"`
	// NoReplyTime is the no reply condition timer of cfnry, 5 to 30 s.
	NoReplyTime int `json:"no_reply_time,omitempty"`
}

ForwardingFeature is TS 29.002 Ext-ForwFeature.

type ForwardingInfo added in v0.5.0

type ForwardingInfo struct {
	SSCode   string              `json:"ss_code"`
	Features []ForwardingFeature `json:"features"`
}

ForwardingInfo is TS 29.002 Ext-ForwInfo: one call forwarding service (SSCode, hex: 21 cfu, 29 cfb, 2a cfnry, 2b cfnrc) and its features.

type ForwardingOptions added in v0.3.0

type ForwardingOptions struct {
	NotifyForwardingParty   bool `json:"notify_forwarding_party,omitempty"`
	RedirectingPresentation bool `json:"redirecting_presentation,omitempty"`
	NotifyCallingParty      bool `json:"notify_calling_party,omitempty"`
	// Reason is notReachable, busy, noReply or unconditional.
	Reason string `json:"reason"`
}

ForwardingOptions is TS 29.002 ForwardingOptions, decoded.

type GatewayError

type GatewayError struct {
	CorrelationID string
	Status        string // StatusTimeout, StatusAborted, ...
	Code          int32  // ErrCode* (negative) or a MAP error code (positive, MAPErr*)
	Message       string
	NodeID        string
}

GatewayError is a failure the gateway reported on a response subject.

func (*GatewayError) Error

func (e *GatewayError) Error() string

type ISDRequest added in v0.5.0

type ISDRequest struct {
	IMSI      string // required
	VLRNumber string // required: E.164 digits
	// VLRPointCode routes on DPC/SSN instead of the VLR number as GT.
	VLRPointCode uint32
	Data         SubscriberData
}

ISDRequest is a stand-alone insertSubscriberData to the VLR serving a subscriber (TS 29.002 §8.8.1): changed or added data.

type ISDResult added in v0.5.0

type ISDResult struct {
	Result *InsertResult // never nil
	NodeID string
	Raw    *Message
}

ISDResult is the VLR's answer.

type InsertResult added in v0.5.0

type InsertResult struct {
	UnsupportedTeleservices   []string `json:"unsupported_teleservices,omitempty"`
	UnsupportedBearerServices []string `json:"unsupported_bearer_services,omitempty"`
	UnsupportedSSCodes        []string `json:"unsupported_ss_codes,omitempty"`
	// UnsupportedODB are the ODB-GeneralData categories it does not support.
	UnsupportedODB []string `json:"unsupported_odb,omitempty"`
	// RegionalSubscriptionResponse: networkNode-AreaRestricted,
	// tooManyZoneCodes, zoneCodesConflict or regionalSubscNotSupported.
	RegionalSubscriptionResponse string   `json:"regional_subscription_response,omitempty"`
	SupportedCAMELPhases         []int    `json:"supported_camel_phases,omitempty"`
	OfferedCAMEL4CSIs            []string `json:"offered_camel4_csis,omitempty"`
}

InsertResult is what a VLR answered to subscriber data (InsertSubscriberDataRes): what it did not take. Data sent in several parts gives one result, the parts' together.

type Location added in v0.2.0

type Location struct {
	// AgeMinutes is the time since the last contact with the subscriber:
	// 0 = in contact now, 32767 = at least that old.
	AgeMinutes *int `json:"age_minutes,omitempty"`
	// VLRNumber and MSCNumber (CS) or SGSNNumber (PS): E.164 digits.
	VLRNumber  string `json:"vlr_number,omitempty"`
	MSCNumber  string `json:"msc_number,omitempty"`
	SGSNNumber string `json:"sgsn_number,omitempty"`
	// At most one of CellGlobalID, ServiceAreaID and LocationArea is set.
	CellGlobalID  *CellGlobalID  `json:"cell_global_id,omitempty"`
	ServiceAreaID *ServiceAreaID `json:"service_area_id,omitempty"`
	LocationArea  *LocationArea  `json:"location_area,omitempty"`
	// RoutingAreaID is the RAI value part (TS 29.060), hex. PS only.
	RoutingAreaID string `json:"routing_area_id,omitempty"`
	// LocationNumber (ITU-T Q.763), hex. CS only.
	LocationNumber string `json:"location_number,omitempty"`
	// GeographicalInformation (TS 23.032 ellipsoid point with uncertainty
	// circle, 8 octets) and GeodeticInformation (Q.763, 10 octets), hex.
	GeographicalInformation string `json:"geographical_information,omitempty"`
	GeodeticInformation     string `json:"geodetic_information,omitempty"`
	// CurrentLocationRetrieved: the location was obtained by paging just now.
	CurrentLocationRetrieved bool `json:"current_location_retrieved,omitempty"`
	// EPS is the E-UTRAN location, when the HLR returned it within the CS
	// location. CS only.
	EPS *LocationEPS `json:"eps,omitempty"`
}

Location is TS 29.002 LocationInformation (CS) or LocationInformationGPRS (PS).

type LocationArea added in v0.2.0

type LocationArea struct {
	MCC string `json:"mcc"`
	MNC string `json:"mnc"`
	LAC uint16 `json:"lac"`
}

LocationArea is a location area identity (TS 23.003).

type LocationEPS added in v0.2.0

type LocationEPS struct {
	// ECGI and TAI as coded in TS 29.118, hex.
	ECGI string `json:"ecgi,omitempty"`
	TAI  string `json:"tai,omitempty"`
	// MMEName is the serving MME's Diameter identity.
	MMEName                  string `json:"mme_name,omitempty"`
	AgeMinutes               *int   `json:"age_minutes,omitempty"`
	GeographicalInformation  string `json:"geographical_information,omitempty"`
	GeodeticInformation      string `json:"geodetic_information,omitempty"`
	CurrentLocationRetrieved bool   `json:"current_location_retrieved,omitempty"`
}

LocationEPS is TS 29.002 LocationInformationEPS.

type LocationUpdate added in v0.5.0

type LocationUpdate struct {
	// DialogueID is the same in every turn of one location update. Opaque,
	// at most 64 characters.
	DialogueID string `json:"dialogue_id,omitempty"`
	Action     string `json:"action"`
	// AnswerBy is when the gateway stops waiting for the answer to a turn;
	// it then refuses the location update with systemFailure.
	AnswerBy *time.Time `json:"answer_by,omitempty"`

	// The update_location turn: what the VLR sent (UpdateLocationArg). The
	// IMSI is in Message.IMSI.
	MSCNumber     *AddressString `json:"msc_number,omitempty"`
	VLRNumber     *AddressString `json:"vlr_number,omitempty"`
	LMSI          string         `json:"lmsi,omitempty"` // hex, 4 octets
	VLRCapability *VLRCapability `json:"vlr_capability,omitempty"`
	// IMEISV is the terminal's IMEISV (16 digits), when the VLR sent it.
	IMEISV                      string `json:"imeisv,omitempty"`
	SkipSubscriberDataUpdate    bool   `json:"skip_subscriber_data_update,omitempty"`
	RestorationIndicator        bool   `json:"restoration_indicator,omitempty"`
	InformPreviousNetworkEntity bool   `json:"inform_previous_network_entity,omitempty"`
	CSLCSNotSupportedByUE       bool   `json:"cs_lcs_not_supported_by_ue,omitempty"`
	// CallingGT is the global title the VLR's request came from (SCCP
	// calling address): GSMA FS.11 screening compares it with VLRNumber.
	CallingGT string `json:"calling_gt,omitempty"`

	// Error is the MAP error of a reject answer.
	Error int32 `json:"error,omitempty"`
	// ErrorCause qualifies Error: a Cause* constant.
	ErrorCause string `json:"error_cause,omitempty"`
	// Detail says why, in an end turn or in an insert_result turn that
	// reports a failure.
	Detail string `json:"detail,omitempty"`
}

LocationUpdate is a location update's part of a Message on SubjectLocationUpdate: a turn, or the application's answer to one.

type LocationUpdateAnswer added in v0.5.0

type LocationUpdateAnswer struct {
	// Insert sends the subscriber data (insertSubscriberData); the next turn
	// is its result. The gateway divides data that does not fit one message
	// into several, and gives one result.
	Insert *SubscriberData
	// Accept ends the location update with updateLocation's result, the
	// gateway's HLR number in it.
	Accept bool
	// Reject ends it with updateLocation's error: MAPErrSystemFailure,
	// MAPErrDataMissing, MAPErrUnexpectedDataValue, MAPErrUnknownSubscriber
	// or MAPErrRoamingNotAllowed.
	Reject int32
	// RejectCause qualifies the Reject: for MAPErrRoamingNotAllowed
	// CausePLMNRoamingNotAllowed (the default), CauseOperatorDeterminedBarring
	// or CauseSupportedRATTypesNotAllowed; for MAPErrUnknownSubscriber,
	// optionally, CauseIMSIUnknown or CauseGPRSEPSSubscriptionUnknown.
	RejectCause string
}

LocationUpdateAnswer is the application's answer to a turn: exactly one of Insert, Accept and Reject.

type LocationUpdateTurn added in v0.5.0

type LocationUpdateTurn struct {
	DialogueID string
	Action     string // ULUpdateLocation, ULInsertResult or ULEnd
	IMSI       string
	// Update is the VLR's request: on every turn.
	Update *LocationUpdate
	// Insert is the VLR's answer to the subscriber data (ULInsertResult
	// with an empty Status).
	Insert *InsertResult
	// Status, Code and Detail: a failure — of the subscriber data
	// (ULInsertResult: StatusRemoteError and the VLR's MAP error, or
	// StatusRejected when the gateway could not send it), or how the
	// location update ended (ULEnd: StatusAborted, StatusTimeout).
	Status string
	Code   int32
	Detail string
	NodeID string
	Raw    *Message
}

LocationUpdateTurn is a turn of a location update as the handler gets it.

type MNPInfo added in v0.2.0

type MNPInfo struct {
	RouteingNumber string `json:"routeing_number,omitempty"`
	IMSI           string `json:"imsi,omitempty"`
	MSISDN         string `json:"msisdn,omitempty"`
	// Status is the NumberPortabilityStatus name: notKnownToBePorted,
	// ownNumberPortedOut, foreignNumberPortedToForeignNetwork,
	// ownNumberNotPortedOut, foreignNumberPortedIn.
	Status string `json:"status,omitempty"`
}

MNPInfo is TS 29.002 MNPInfoRes.

type MTRequest

type MTRequest struct {
	IMSI                 string        // required, from SRIResult.IMSI
	NetworkNodeNumber    AddressString // required, from SRIResult.NetworkNodeNumber
	ServiceCentreAddress AddressString // required
	TPDU                 []byte        // required, SMS-DELIVER TPDU (3GPP TS 23.040), opaque to the gateway
	// MSCPointCode overrides the destination point code. Zero routes on the
	// network node number GT alone.
	MSCPointCode uint32
}

MTRequest is a MAP MT-ForwardSM request (3GPP TS 29.002 §12.9).

type MTResult

type MTResult struct {
	Status string // StatusDelivered
	NodeID string
	Raw    *Message
}

MTResult is a successful MT-ForwardSM answer.

type Message

type Message struct {
	MessageID     string      `json:"message_id"`
	CorrelationID string      `json:"correlation_id,omitempty"`
	MessageType   MessageType `json:"message_type"`
	Direction     Direction   `json:"direction"`
	Timestamp     time.Time   `json:"timestamp"`

	// Addressing (E.164 digits).
	Sender    string `json:"sender,omitempty"`
	Recipient string `json:"recipient,omitempty"`
	IMSI      string `json:"imsi,omitempty"`
	MSISDN    string `json:"msisdn,omitempty"`

	// SS7 routing overrides. Zero/empty means "use the gateway's configuration".
	OPC         uint32 `json:"opc,omitempty"`
	DPC         uint32 `json:"dpc,omitempty"`
	SSN         uint8  `json:"ssn,omitempty"`
	GlobalTitle string `json:"global_title,omitempty"`

	Content     string                 `json:"content,omitempty"`
	PayloadData []byte                 `json:"payload_data,omitempty"` // base64 in JSON
	Parameters  map[string]interface{} `json:"parameters,omitempty"`

	ServiceKey uint32 `json:"service_key,omitempty"`
	EventType  string `json:"event_type,omitempty"`

	// Location interface (map.ati.*, map.psi.*): what a request asks for
	// and what the answer carries. SubscriberInfo is also in a call routing
	// answer when the HLR returns the subscriber's location or state.
	RequestedInfo  *RequestedInfo  `json:"requested_info,omitempty"`
	SubscriberInfo *SubscriberInfo `json:"subscriber_info,omitempty"`

	// Call routing (map.routing.*): the answer's routing information. The
	// answer's IMSI is in IMSI, its location and state, if any, in
	// SubscriberInfo.
	RoutingInfo *RoutingInfo `json:"routing_info,omitempty"`

	// USSD (map.ussd.*): the session, the action, and the text.
	USSD *USSD `json:"ussd,omitempty"`

	// Location management with the gateway as HLR: a location update's
	// turn or answer (map.ul); the subscriber data of an insert (map.ul
	// answer, map.isd.request) and the VLR's answer to it (map.ul turn,
	// map.isd.response); cancelLocation's and provideRoamingNumber's fields
	// (map.cl.*, map.prn.*).
	LocationUpdate       *LocationUpdate       `json:"location_update,omitempty"`
	SubscriberData       *SubscriberData       `json:"subscriber_data,omitempty"`
	InsertResult         *InsertResult         `json:"insert_result,omitempty"`
	CancelLocation       *CancelLocation       `json:"cancel_location,omitempty"`
	RoamingNumberEnquiry *RoamingNumberEnquiry `json:"roaming_number_enquiry,omitempty"`

	// Authentication and MS purging with the gateway as HLR: a
	// sendAuthenticationInfo or purgeMS and the application's answer
	// (map.sai, map.purge).
	Authentication *Authentication `json:"authentication,omitempty"`
	Purge          *Purge          `json:"purge,omitempty"`

	Status       string `json:"status,omitempty"`
	ErrorCode    int32  `json:"error_code,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`

	TraceID string `json:"trace_id,omitempty"`
	NodeID  string `json:"node_id,omitempty"` // gateway node that handled the dialogue
}

Message is the JSON document carried on every subject. Field names and JSON tags are the wire contract shared with non-Go consumers; changing one breaks them.

type MessageType

type MessageType string

MessageType identifies the operation a Message belongs to.

const (
	MsgTypeMAPSendAuthenticationInfo MessageType = "MAP_SAI"
	MsgTypeMAPPurgeMS                MessageType = "MAP_PURGE"
)
const (
	MsgTypeMAPATI MessageType = "MAP_ATI"
	MsgTypeMAPPSI MessageType = "MAP_PSI"
)
const (
	MsgTypeMAPSRI   MessageType = "MAP_SRI"
	MsgTypeMAPMTSMS MessageType = "MAP_MT_SMS"
	MsgTypeMAPMOSMS MessageType = "MAP_MO_SMS"
)
const (
	MsgTypeMAPUpdateLocation       MessageType = "MAP_UL"
	MsgTypeMAPCancelLocation       MessageType = "MAP_CL"
	MsgTypeMAPProvideRoamingNumber MessageType = "MAP_PRN"
	MsgTypeMAPInsertSubscriberData MessageType = "MAP_ISD"
)
const MsgTypeMAPRouting MessageType = "MAP_ROUTING"

MsgTypeMAPRouting requests carry msisdn and, optionally, global_title and dpc (the HLR's address). The gateway ignores every other request field — opc, ssn, sender, recipient, parameters: the SendRoutingInfo it sends is a basic call interrogation whose GMSC address is its own.

const MsgTypeMAPUSSD MessageType = "MAP_USSD"

type ODB added in v0.5.0

type ODB struct {
	General []string `json:"general"`
	HPLMN   []string `json:"hplmn,omitempty"`
}

ODB is TS 29.002 ODB-Data: the operator determined barring categories that apply, by ASN.1 name. General is ODB-GeneralData (allOG-CallsBarred, internationalOGCallsBarred, …); HPLMN is ODB-HPLMN-Data (plmn-SpecificBarringType1 … 4).

type Option

type Option func(*Client)

Option configures a Client.

func WithDecodeErrorHandler

func WithDecodeErrorHandler(f func(subject string, data []byte, err error)) Option

WithDecodeErrorHandler receives messages on the client's subscriptions that are not valid JSON Messages. Without it they are dropped.

func WithDefaultTimeout

func WithDefaultTimeout(d time.Duration) Option

WithDefaultTimeout replaces DefaultTimeout for requests without a deadline.

func WithUSSDTimeout added in v0.4.0

func WithUSSDTimeout(d time.Duration) Option

WithUSSDTimeout replaces DefaultUSSDTimeout for USSD calls without a deadline.

type PRNRequest added in v0.5.0

type PRNRequest struct {
	IMSI      string // required
	VLRNumber string // required: E.164 digits
	// VLRPointCode routes on DPC/SSN instead of the VLR number as GT.
	VLRPointCode uint32
	// Enquiry carries the argument; MSCNumber is required (the MSC number
	// the location update gave).
	Enquiry RoamingNumberEnquiry
}

PRNRequest is a provideRoamingNumber to the VLR serving a subscriber (TS 29.002 §10.2).

type PRNResult added in v0.5.0

type PRNResult struct {
	RoamingNumber             AddressString
	VMSCAddress               *AddressString
	ReleaseResourcesSupported bool
	NodeID                    string
	Raw                       *Message
}

PRNResult is a roaming number.

type PSIRequest added in v0.2.0

type PSIRequest struct {
	IMSI string // required
	// VLRNumber is the serving VLR's address (required). For a combined
	// MSC/VLR it is normally the network node number SendRoutingInfoForSM
	// returned.
	VLRNumber AddressString
	// Requested selects what to ask for. MNP is not available here.
	Requested RequestedInfo
	// VLRPointCode routes on point code instead of the VLR number GT.
	VLRPointCode uint32
}

PSIRequest is a MAP ProvideSubscriberInfo towards the VLR serving the subscriber (3GPP TS 29.002 §8.11.2).

type Purge added in v0.6.0

type Purge struct {
	DialogueID string     `json:"dialogue_id,omitempty"`
	AnswerBy   *time.Time `json:"answer_by,omitempty"`

	// The request: the VLR's number when a VLR sends it, the SGSN's when
	// an SGSN does.
	VLRNumber  *AddressString `json:"vlr_number,omitempty"`
	SGSNNumber *AddressString `json:"sgsn_number,omitempty"`
	CallingGT  string         `json:"calling_gt,omitempty"`

	// The answer: what to freeze (TS 29.002 §8.1.6.3 — the TMSI when the
	// VLR number is the one stored, the P-TMSI likewise for the SGSN), or
	// Error.
	FreezeTMSI  bool   `json:"freeze_tmsi,omitempty"`
	FreezePTMSI bool   `json:"freeze_ptmsi,omitempty"`
	FreezeMTMSI bool   `json:"freeze_mtmsi,omitempty"`
	Error       int32  `json:"error,omitempty"`
	ErrorCause  string `json:"error_cause,omitempty"` // a Cause* qualifying Error
	Detail      string `json:"detail,omitempty"`
}

Purge is a purgeMS's part of a Message on SubjectPurge: the request, or the application's answer to it.

type PurgeAnswer added in v0.6.0

type PurgeAnswer struct {
	FreezeTMSI, FreezePTMSI, FreezeMTMSI bool
	// Reject refuses the request with one of purgeMS's errors:
	// MAPErrDataMissing, MAPErrUnexpectedDataValue or
	// MAPErrUnknownSubscriber.
	Reject int32
	// RejectCause qualifies a MAPErrUnknownSubscriber: CauseIMSIUnknown or
	// CauseGPRSEPSSubscriptionUnknown. Optional.
	RejectCause string
}

PurgeAnswer is the application's answer: what to freeze, or Reject.

type PurgeRequest added in v0.6.0

type PurgeRequest struct {
	DialogueID string
	IMSI       string
	Request    *Purge
	NodeID     string
	Raw        *Message
}

PurgeRequest is a purgeMS as the handler gets it.

type RequestedInfo added in v0.2.0

type RequestedInfo struct {
	// Location asks for the location information of Domain.
	Location bool `json:"location,omitempty"`
	// CurrentLocation asks the serving node to page the subscriber for an
	// up-to-date location instead of the last known one. Requires Location.
	CurrentLocation bool `json:"current_location,omitempty"`
	// EPSLocation tells the HLR that the E-UTRAN location may be returned,
	// in Location.EPS or in SubscriberInfo.LocationEPS. Requires Location.
	EPSLocation bool `json:"eps_location,omitempty"`
	// State asks for the subscriber state of Domain.
	State bool `json:"state,omitempty"`
	// Domain is DomainCS (the default when empty) or DomainPS.
	Domain string `json:"domain,omitempty"`
	// IMEI asks for the equipment identity.
	IMEI bool `json:"imei,omitempty"`
	// MSClassmark asks for MS Classmark 2, returned for the CS domain.
	MSClassmark bool `json:"ms_classmark,omitempty"`
	// MNP asks for number portability information. AnyTimeInterrogation only.
	MNP bool `json:"mnp,omitempty"`
}

RequestedInfo selects what an AnyTimeInterrogation or ProvideSubscriberInfo asks for (TS 29.002 RequestedInfo). At least one item must be set.

type Resynchronisation added in v0.6.0

type Resynchronisation struct {
	RAND string `json:"rand"`
	AUTS string `json:"auts"`
}

Resynchronisation is re-synchronisationInfo: RAND 16 octets, AUTS 14.

type RoamingNumberEnquiry added in v0.5.0

type RoamingNumberEnquiry struct {
	// Request (ProvideRoamingNumberArg). The IMSI is in Message.IMSI.
	MSCNumber                 *AddressString `json:"msc_number,omitempty"`
	MSISDN                    *AddressString `json:"msisdn,omitempty"`
	LMSI                      string         `json:"lmsi,omitempty"` // hex, 4 octets
	GMSCAddress               *AddressString `json:"gmsc_address,omitempty"`
	CallReferenceNumber       string         `json:"call_reference_number,omitempty"` // hex, 1..8 octets
	ORInterrogation           bool           `json:"or_interrogation,omitempty"`
	SuppressionOfAnnouncement bool           `json:"suppression_of_announcement,omitempty"`
	// BearerCapability is gsm-BearerCapability: the ExternalSignalInfo
	// protocol (1 gsm-0408, 2 gsm-0806, 3 gsm-BSSMAP, 4 ets-300102-1) and
	// signal octets, hex.
	BearerCapability *SignalInfo `json:"bearer_capability,omitempty"`

	// Answer (ProvideRoamingNumberRes).
	RoamingNumber             *AddressString `json:"roaming_number,omitempty"`
	VMSCAddress               *AddressString `json:"vmsc_address,omitempty"`
	ReleaseResourcesSupported bool           `json:"release_resources_supported,omitempty"`
}

RoamingNumberEnquiry is ProvideRoamingNumber's part of a Message: the request's fields, and the answer's.

type RoutingInfo added in v0.3.0

type RoutingInfo struct {
	// RoamingNumber is the MSRN to route the call on. From a number
	// portability database it is the routing number followed by the MSISDN,
	// or the MSISDN alone.
	RoamingNumber *AddressString `json:"roaming_number,omitempty"`
	// Forwarding: the call is to be forwarded.
	Forwarding *ForwardingData `json:"forwarding,omitempty"`
	// CAMEL: the subscriber has terminating CAMEL services the GMSC is to
	// invoke before routing. The gateway does not ask for them (it does not
	// offer CAMEL support in the request), so an HLR should not return this.
	CAMEL *CAMELRouting `json:"camel,omitempty"`
	// VMSCAddress is the E.164 address of the MSC serving the subscriber,
	// digits only (as Location.VLRNumber).
	VMSCAddress string `json:"vmsc_address,omitempty"`
	// MSISDN is the subscriber's basic MSISDN, when the HLR returns it.
	MSISDN string `json:"msisdn,omitempty"`
	// ForwardingInterrogationRequired: the HLR asks the GMSC to interrogate
	// it again, for forwarding, if the call is later forwarded.
	ForwardingInterrogationRequired bool `json:"forwarding_interrogation_required,omitempty"`
	// NumberPortabilityStatus is the TS 29.002 NumberPortabilityStatus name:
	// notKnownToBePorted, ownNumberPortedOut or foreignNumberPortedToForeignNetwork.
	NumberPortabilityStatus string `json:"number_portability_status,omitempty"`
	// BasicService is the service the HLR resolved the call to.
	BasicService *BasicService `json:"basic_service,omitempty"`
	// SSCodes are the supplementary services active for the call (TS 29.002
	// SS-Code, one octet each), hex.
	SSCodes []string `json:"ss_codes,omitempty"`
}

RoutingInfo is the routing part of a SendRoutingInfo answer (TS 29.002 SendRoutingInfoRes). The IMSI is in Message.IMSI and, when the HLR returns it, the subscriber's location and state in Message.SubscriberInfo. At most one of RoamingNumber, Forwarding and CAMEL is set.

type RoutingRequest added in v0.3.0

type RoutingRequest struct {
	MSISDN string // required, E.164 digits
	// HLRGlobalTitle and HLRPointCode address the HLR directly. Without
	// them the gateway routes on the MSISDN as global title (or uses
	// map.hlr_gt / map.hlr_pc when map.sri_routing is "hlr").
	HLRGlobalTitle string
	HLRPointCode   uint32
}

RoutingRequest is a MAP SendRoutingInfo towards the subscriber's HLR (3GPP TS 29.002 §10.1), with the gateway as GMSC.

type RoutingResult added in v0.3.0

type RoutingResult struct {
	IMSI    string       // the subscriber's IMSI; empty if the HLR left it out
	Routing *RoutingInfo // never nil
	// SubscriberInfo is the location and state the HLR returned, if any.
	SubscriberInfo *SubscriberInfo
	NodeID         string // gateway node that ran the dialogue
	Raw            *Message
}

RoutingResult is a successful SendRoutingInfo answer.

type SRIRequest

type SRIRequest struct {
	MSISDN               string        // required, E.164 digits
	ServiceCentreAddress AddressString // required
	// HLRGlobalTitle and HLRPointCode override the gateway's map.hlr_gt and
	// map.hlr_pc for this request. Leave empty to use the configuration.
	HLRGlobalTitle string
	HLRPointCode   uint32
}

SRIRequest is a MAP SendRoutingInfoForSM request (3GPP TS 29.002 §12.1).

type SRIResult

type SRIResult struct {
	IMSI string
	// NetworkNodeNumber is the serving MSC/VLR address digits; pass it to
	// MTRequest.NetworkNodeNumber.
	NetworkNodeNumber string
	NodeID            string // gateway node that ran the dialogue
	Raw               *Message
}

SRIResult is a successful SendRoutingInfoForSM answer.

type SSData added in v0.5.0

type SSData struct {
	SSCode string   `json:"ss_code"`
	Status SSStatus `json:"status"`
	// CLIRestriction is clir's option: permanent, temporaryDefaultRestricted
	// or temporaryDefaultAllowed. OverrideCategory (overrideEnabled or
	// overrideDisabled) is the alternative: at most one of them.
	CLIRestriction   string         `json:"cli_restriction,omitempty"`
	OverrideCategory string         `json:"override_category,omitempty"`
	BasicServices    []BasicService `json:"basic_services,omitempty"`
}

SSData is TS 29.002 Ext-SS-Data: a supplementary service other than call forwarding and barring (SSCode, hex: 11 clip, 12 clir, 41 cw, 42 hold, 51 multiPTY).

type SSStatus added in v0.5.0

type SSStatus struct {
	Provisioned bool `json:"provisioned,omitempty"` // P
	Registered  bool `json:"registered,omitempty"`  // R
	Active      bool `json:"active,omitempty"`      // A
	Quiescent   bool `json:"quiescent,omitempty"`   // Q
}

SSStatus is TS 29.002 Ext-SS-Status: the TS 23.011 state bits.

type ServiceAreaID added in v0.2.0

type ServiceAreaID struct {
	MCC string `json:"mcc"`
	MNC string `json:"mnc"`
	LAC uint16 `json:"lac"`
	SAC uint16 `json:"sac"`
}

ServiceAreaID is a service area identity (TS 23.003): SAC is the service area code.

type SignalInfo added in v0.5.0

type SignalInfo struct {
	ProtocolID int    `json:"protocol_id"`
	Data       string `json:"data"` // hex, 1..200 octets
}

SignalInfo is TS 29.002 ExternalSignalInfo.

type SubscriberData added in v0.5.0

type SubscriberData struct {
	MSISDN *AddressString `json:"msisdn,omitempty"`
	// Category is the ITU-T Q.763 calling party's category, hex (0a:
	// ordinary subscriber).
	Category string `json:"category,omitempty"`
	// SubscriberStatus is serviceGranted or operatorDeterminedBarring (then
	// ODB is required).
	SubscriberStatus string `json:"subscriber_status,omitempty"`
	// BearerServices and Teleservices are Ext-BearerServiceCode and
	// Ext-TeleserviceCode values, hex (11: telephony, 21:
	// shortMessageMT-PP, 22: shortMessageMO-PP).
	BearerServices []string          `json:"bearer_services,omitempty"`
	Teleservices   []string          `json:"teleservices,omitempty"`
	Forwarding     []ForwardingInfo  `json:"forwarding,omitempty"`
	CallBarring    []CallBarringInfo `json:"call_barring,omitempty"`
	SSData         []SSData          `json:"ss_data,omitempty"`
	ODB            *ODB              `json:"odb,omitempty"`
	// RoamingRestrictedUnsupportedFeature is
	// roamingRestrictionDueToUnsupportedFeature.
	RoamingRestrictedUnsupportedFeature bool `json:"roaming_restricted_unsupported_feature,omitempty"`
	// RegionalSubscription are zone codes (TS 23.003 §4.4), hex, 2 octets
	// each; at most 10.
	RegionalSubscription []string `json:"regional_subscription,omitempty"`
	// NetworkAccessMode is packetAndCircuit, onlyCircuit or onlyPacket.
	NetworkAccessMode string `json:"network_access_mode,omitempty"`
	// AccessRestriction are AccessRestrictionData names: utranNotAllowed,
	// geranNotAllowed, ganNotAllowed, i-hspa-evolutionNotAllowed,
	// wb-e-utranNotAllowed, ho-toNon3GPP-AccessNotAllowed,
	// nb-iotNotAllowed, enhancedCoverageNotAllowed.
	AccessRestriction []string `json:"access_restriction,omitempty"`
}

SubscriberData is the circuit-switched subscriber data the gateway sends a VLR in insertSubscriberData (TS 29.002 SubscriberData, §8.8.1.3 for what each field means and when to send it). Codes are hex, one octet each unless the type allows more; names are the ASN.1 value names. CUG, eMLPP, VBS/VGCS and CAMEL subscription information are not carried.

type SubscriberInfo added in v0.2.0

type SubscriberInfo struct {
	// Location is the circuit-switched location (MSC/VLR).
	Location *Location `json:"location,omitempty"`
	// State is the circuit-switched subscriber state.
	State *SubscriberState `json:"state,omitempty"`
	// LocationGPRS is the packet-switched location (SGSN).
	LocationGPRS *Location `json:"location_gprs,omitempty"`
	// PSState is the packet-switched subscriber state.
	PSState *SubscriberState `json:"ps_state,omitempty"`
	// EPSState is the EPS subscriber state.
	EPSState *SubscriberState `json:"eps_state,omitempty"`
	// LocationEPS is the EPS location returned outside Location.
	LocationEPS *LocationEPS `json:"location_eps,omitempty"`
	// IMEI digits (TS 23.003), 15 or 16 of them.
	IMEI string `json:"imei,omitempty"`
	// MSClassmark2 is the value part of the MS Classmark 2 IE (TS 24.008), hex.
	MSClassmark2 string `json:"ms_classmark2,omitempty"`
	// MNP is the number portability information.
	MNP *MNPInfo `json:"mnp,omitempty"`
}

SubscriberInfo is the answer to an AnyTimeInterrogation or a ProvideSubscriberInfo (TS 29.002 SubscriberInfo): only what was requested and what the network knows is present. Octet strings whose layout another specification defines are passed through as lowercase hex.

type SubscriberInfoResult added in v0.2.0

type SubscriberInfoResult struct {
	Info   *SubscriberInfo // never nil
	NodeID string          // gateway node that ran the dialogue
	Raw    *Message
}

SubscriberInfoResult is a successful AnyTimeInterrogation or ProvideSubscriberInfo answer.

type SubscriberState added in v0.2.0

type SubscriberState struct {
	State              string `json:"state"`
	NotReachableReason string `json:"not_reachable_reason,omitempty"`
}

SubscriberState is TS 29.002 SubscriberState (CS) or PS-SubscriberState (PS, EPS). State is the ASN.1 name of the alternative:

  • CS: assumedIdle, camelBusy, netDetNotReachable, notProvidedFromVLR;
  • PS/EPS: notProvidedFromSGSNorMME, ps-Detached, ps-AttachedNotReachableForPaging, ps-AttachedReachableForPaging, ps-PDP-ActiveNotReachableForPaging, ps-PDP-ActiveReachableForPaging, netDetNotReachable.

NotReachableReason accompanies netDetNotReachable: msPurged, imsiDetached, restrictedArea or notRegistered.

type SuperCharger added in v0.5.0

type SuperCharger struct {
	SendSubscriberData bool   `json:"send_subscriber_data,omitempty"`
	SubscriberDataAge  string `json:"subscriber_data_age,omitempty"`
}

SuperCharger is TS 29.002 SuperChargerInfo: the VLR asks for the data, or holds data of the given age (AgeIndicator, hex).

type USSD added in v0.4.0

type USSD struct {
	SessionID string `json:"session_id,omitempty"`
	Action    string `json:"action"`
	// Route is the route a session belongs to (events, and a start that
	// names one).
	Route string `json:"route,omitempty"`
	// DCS and Data are the USSD data coding scheme (TS 23.038 §5) and the
	// USSD-String (base64 in JSON). An answer without them is an empty
	// reply, which unstructuredSS-Request allows.
	DCS  *byte  `json:"dcs,omitempty"`
	Data []byte `json:"data,omitempty"`
	// Text is Data decoded, when the DCS is GSM 7-bit or UCS2. A language
	// indication the DCS announces (0x10, 0x11) stays at its start. In a
	// command, Text alone asks the gateway to encode it (GSM 7-bit when
	// every character is in the default alphabet, else UCS2).
	Text string `json:"text,omitempty"`
	// Error is the MAP error of a reject command.
	Error int32 `json:"error,omitempty"`
	// Detail says who released a session, in an end event; in a begin, why
	// Text is missing when the string could not be decoded.
	Detail string `json:"detail,omitempty"`
}

USSD is the USSD part of a Message on the USSD subjects.

type USSDAnswer added in v0.4.0

type USSDAnswer struct {
	SessionID string
	Reply     *USSDMessage // nil for a notify
	NodeID    string
	Raw       *Message
}

USSDAnswer is the outcome of a request or notify: the session, and for a request what the subscriber replied (possibly Empty).

type USSDEvent added in v0.4.0

type USSDEvent struct {
	SessionID string
	Action    string // USSDBegin or USSDEnd
	Route     string
	// Begin: the subscriber — the IMSI or MSISDN of the HLR's destination
	// reference, the MSISDN of its argument; either may be missing — and
	// what they sent.
	MSISDN, IMSI string
	Message      *USSDMessage
	// End: how (see Endings).
	Status string
	Code   int32
	Detail string
	NodeID string
	Raw    *Message
}

USSDEvent is a session begin or end.

type USSDMessage added in v0.4.0

type USSDMessage struct {
	// Empty: the reply carried no USSD string.
	Empty bool
	DCS   byte
	Data  []byte
	// Text is Data decoded; empty when the DCS is not GSM 7-bit or UCS2.
	Text string
}

USSDMessage is what the subscriber sent.

type USSDStart added in v0.4.0

type USSDStart struct {
	// Exactly one of MSISDN and IMSI (digits) identifies the subscriber. The
	// HLR is addressed by the MSISDN as global title, or by map.hlr_gt /
	// map.hlr_pc (map.sri_routing "hlr"); a start by IMSI needs the latter.
	MSISDN, IMSI string
	// Notify sends unstructuredSS-Notify instead of unstructuredSS-Request.
	Notify  bool
	Message USSDText
	// Route receives the session's end event; USSDDefaultRoute when empty.
	Route string
}

USSDStart is a network-initiated session.

type USSDText added in v0.4.0

type USSDText struct {
	Text string
	DCS  *byte
	Data []byte
}

USSDText is what an application sends: Text for the gateway to encode, or DCS and Data as they are to go out. The gateway's length check, on the encoded octets, is authoritative.

type VLRCapability added in v0.5.0

type VLRCapability struct {
	// SupportedCAMELPhases are the CAMEL phase numbers, 1 to 4.
	SupportedCAMELPhases []int `json:"supported_camel_phases,omitempty"`
	// OfferedCAMEL4CSIs are the ASN.1 names: o-csi, d-csi, vt-csi, t-csi,
	// mt-sms-csi, mg-csi, psi-enhancements.
	OfferedCAMEL4CSIs []string `json:"offered_camel4_csis,omitempty"`
	// SupportedRATTypes are the ASN.1 names: utran, geran, gan,
	// i-hspa-evolution, e-utran, nb-iot.
	SupportedRATTypes []string `json:"supported_rat_types,omitempty"`
	// SupportedLCSCapabilitySets are the set numbers, 1 to 5.
	SupportedLCSCapabilitySets   []int `json:"supported_lcs_capability_sets,omitempty"`
	LongFTNSupported             bool  `json:"long_ftn_supported,omitempty"`
	MSISDNLessOperationSupported bool  `json:"msisdn_less_operation_supported,omitempty"`
	MTRoamingForwardingSupported bool  `json:"mt_roaming_forwarding_supported,omitempty"`
	SOLSASupported               bool  `json:"solsa_supported,omitempty"`
	LongGroupIDSupported         bool  `json:"long_group_id_supported,omitempty"`
	ResetIDsSupported            bool  `json:"reset_ids_supported,omitempty"`
	// ISTSupport is basicISTSupported or istCommandSupported.
	ISTSupport string `json:"ist_support,omitempty"`
	// SuperCharger is the VLR's Super-Charger information (TS 23.116).
	SuperCharger *SuperCharger `json:"super_charger,omitempty"`
}

VLRCapability is TS 29.002 VLR-Capability.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址