Category Archives: Mobile Networks

Huawei BBU 3900 Architecture

Huawei Baseband Cheat Sheet

Baseband Units (UBBP)

CardMax LTE Cells
UBBPd33×20 MHz 2T2R
UBBPd43×20 MHz 4T4R
UBBPd56×20 MHz 2T2R OR 3×20 MHz 4T4R
UBBPd66×20 MHz 4T4R
UBBPe13×20 MHz 2T2R
UBBPe23×20 MHz 4T4R
UBBPe36×20 MHz 2T2R OR 3×20 MHz 4T4R
UBBPe46×20 MHz 4T4R OR 3×20 MHz 8T8R
Max Cells in LTE FDD

Main Processing and Transmission (LMPT/UMPT)

In some instances two boards can be used together to double the max cells or max throughput values.

CardMax CellsMax Throughput
(at MAC Layer)
Max UEs
(In RRC Connected)
LMPT18 Cells (4T4R)Uplink 300Mbps
Downlink 450Mbps
5400
UMPTa36 Cells (4T4R)Aggregate 1.5Gbps10800
UMPTb136 Cells (4T4R)Aggregate 1.5Gbps10800
UMPTb236 Cells (4T4R)Aggregate 1.5Gbps10800
UMPTb336 Cells (4T4R)Aggregate 2Gbps10800
UMPTb936 Cells (4T4R)Aggregate 2Gbps10800
UMPTe72 Cells (4T4R)Aggregate 10Gbps14400

Lifecycle of a Dedicated Bearer – From Flow-Description AVP to Traffic Flow Templates

To support Dedicated Bearers we first have to have a way of profiling the traffic, to classify the traffic as being the type we want to provide the Dedicated Bearer for.

The first step involves a request from an Application Function (AF) to the PCRF via the Rx interface.

The most common type of AF would be a P-CSCF. When a VoLTE call gets setup the P-CSCF requests that a dedicated bearer be setup for the IP Address and Ports involved in the VoLTE call, to ensure users get the best possible call quality.

But Application Functions aren’t limited to just VoLTE – You could also embed an Application Function into the server for an online game to enable a dedicated bearer for users playing that game, or a sports streaming app that detects when a user starts streaming sports and creates a dedicated bearer for that user to send the traffic down.

The request to setup a dedicated bearer comes in the form of a Diameter request message from the AF, using the Rx reference point, typically from the P-CSCF to the PCRF in the network in an “AA-Request”.

Of main interest in the AA-Request is the Media Component AVP, that contains all the details needed to identify the traffic flow.

Now our PCRF is in charge of policy, and know which P-GW is serving the required subscriber. So the PCRF takes this information and sends a Gx Re-Auth Request to the PCEF in the P-GW serving the subscriber, with a Charging Rule the PCEF in the P-GW needs to install, to profile and apply QoS to the bearer.

So within the Gx Re-Auth Request is the Charging-Rule Definition, made up of Flow-Description AVP which I’ve written about here, that is used to identify and profile traffic flows and QoS parameters to apply to matching traffic.

Charging Rule Definition’s Flow-Information AVPs showing the information needed to profile the traffic

The QoS Description AVP defines which QoS parameters (QCI / ARP / Guaranteed & Maximum Bandwidth) should be applied to the traffic that matches the rules we just defined.

QoS information AVP
QoS Information AVP showing requested QoS Parameters

The P-GW sends back a Gx Re-Auth Answer, and gets to work actually setting up these bearers.

With the rule installed on the PCEF, it’s time to get this new bearer set up on the UE / eNodeB.

The P-GW sends a GTPv2 “Create Bearer Request” to the S-GW which forwards it onto the MME, to setup / define the Dedicated Bearer to be setup on the eNodeB.

GTPv2 “Create Bearer Request” sent by the P-Gw to the S-GW forwarded from the S-GW to the MME

The MME translates this into an S1 “E-RAB Setup Request” which it sends to the eNodeB to setup,

S1 E-RAB Setup request showing the E-RAB to be setup

Assuming the eNodeB has the resources to setup this bearer, it provides the details to the UE and sets up the bearer, sending confirmation back to the MME in the S1 “E-RAB Setup Response” message, which the MME translates back into GTPv2 for a “Create Bearer Response”

All this effort to keep your VoLTE calls sounding great!

Some thoughts on NRF Security in 5G Core

So I’ve been waxing lyrical about how cool in the NRF is, but what about how it’s secured?

A matchmaking service for service-consuming NFs to find service-producing NFs makes integration between them a doddle, but also opens up all sorts of attack vectors.

Theoretical Nasty Attacks (PoC or GTFO)

Sniffing Signaling Traffic:
A malicious actor could register a fake UDR service with a higher priority with the NRF. This would mean UDR service consumers (Like the AUSF or UDM) would send everything to our fake UDR, which could then proxy all the requests to the real UDR which has a lower priority, all while sniffing all the traffic.

Stealing SIM Credentials:
Brute forcing the SUPI/IMSI range on a UDR would allow the SIM Card Crypto values (K/OP/Private Keys) to be extracted.

Sniffing User Traffic:
A dodgy SMF could select an attacker-controlled / run UPF to sniff all the user traffic that flows through it.

Obviously there’s a lot more scope for attack by putting nefarious data into the NRF, or querying it for data gathering, and I’ll see if I can put together some examples in the future, but you get the idea of the mischief that could be managed through the NRF.

This means it’s pretty important to secure it.

OAuth2

3GPP selected to use common industry standards for HTTP Auth, including OAuth2 (Clearly lessons were learned from COMP128 all those years ago), however OAuth2 is optional, and not integrated as you might expect. There’s a little bit to it, but you can expect to see a post on the topic in the next few weeks.

3GPP Security Recommendations

So how do we secure the NRF from bad actors?

Well, there’s 3 options according to 3GPP:

Option 1 – Mutual TLS

Where the Client (NF) and the Server (NRF) share the same TLS info to communicate.

This is a pretty standard mechanism to use for securing communications, but the reliance on issuing certificates and distributing them is often done poorly and there is no way to ensure the person with the certificate, is the person the certificate was issued to.

3GPP have not specified a mechanism for issuing and securely distributing certificates to NFs.

Option 2 – Network Domain Security (NDS)

Split the network traffic on a logical level (VLANs / VRFs, etc) so only NFs can access the NRF.

Essentially it’s logical network segregation.

Option 3 – Physical Security

Split the network like in NDS but a physical layer, so the physical cables essentially run point-to-point from NF to NRF.

Thoughts?

What’s interesting is these are presented as 3 options, rather than the layered approach.

OAuth2 is used, but

Summary


NRF and NF shall authenticate each other during discovery, registration, and access token request. If the PLMN uses
protection at the transport layer as described in clause 13.1, authentication provided by the transport layer protection
solution shall be used for mutual authentication of the NRF and NF.
If the PLMN does not use protection at the transport layer, mutual authentication of NRF and NF may be implicit by
NDS/IP or physical security (see clause 13.1).
When NRF receives message from unauthenticated NF, NRF shall support error handling, and may send back an error
message. The same procedure shall be applied vice versa.
After successful authentication between NRF and NF, the NRF shall decide whether the NF is authorized to perform
discovery and registration.
In the non-roaming scenario, the NRF authorizes the Nnrf_NFDiscovery_Request based on the profile of the expected
NF/NF service and the type of the NF service consumer, as described in clause 4.17.4 of TS23.502 [8].In the roaming
scenario, the NRF of the NF Service Provider shall authorize the Nnrf_NFDiscovery_Request based on the profile of
the expected NF/NF Service, the type of the NF service consumer and the serving network ID.
If the NRF finds NF service consumer is not allowed to discover the expected NF instances(s) as described in clause
4.17.4 of TS 23.502[8], NRF shall support error handling, and may send back an error message.
NOTE 1: When a NF accesses any services (i.e. register, discover or request access token) provided by the NRF ,
the OAuth 2.0 access token for authorization between the NF and the NRF is not needed.

TS 133 501 – 13.3.1 Authentication and authorization between network functions and the NRF

If you like Pina Coladas, and service the control plane – Intro to NRF in 5GC

The Network Repository Function plays matchmaker to all the elements in our 5G Core.

For our 5G Service-Based-Architecture (SBA) we use Service Based Interfaces (SBIs) to communicate between Network Functions. Sometimes a Network Function acts as a server for these interfaces (aka “Service Producer”) and sometimes it acts as a client on these interfaces (aka “Service Consumer”).

For service consumers to be able to find service producers (Clients to be able to find servers), we need a directory mechanism for clients to be able to find the servers to serve their needs, this is the role of the NRF.

With every Service Producer registering to the NRF, the NRF has knowledge of all the available Service Producers in the network, so when a Service Consumer NF comes along (Like an AMF looking for UDM), it just queries the NRF to get the details of who can serve it.

Basic Process – NRF Registration

In order to be found, a service producer NF has to register with the NRF, so the NRF has enough info on the service-producer to be able to recommend it to service-consumers.

This is all the basic info, the Service Based Interfaces (SBIs) that this NF serves, the PLMN, and the type of NF.

The NRF then stores this information in a database, ready to be found by SBI Service Consumers.

This is achieved by the Service Producing NF sending a HTTP2 PUT to the NRF, with the message body containing all the particulars about the services it offers.

Simplified example of an SMSc registering with the NRF in a 5G Core

Basic Process – NRF Discovery

With an NRF that has a few SBI Service Producers registered in it, we can now start querying it from SBI Service Consumers, to find SBI Service Producers.

The SBI Service Consumer looking for a SBI Service Producer, queries the NRF with a little information about itself, and the SBI Service Producer it’s looking for.

For example a SMF looking for a UDM, sends a request like:

http://[::1]:7777/nnrf-disc/v1/nf-instances?requester-nf-type=SMF&target-nf-type=UDM

To the NRF, and the NRF responds with SBI Service Producing NFs that match in JSON body of the response.

SMSF being found by the AMF using the NRF

More Info

I’ve written in a more technical detail on the NRF in this post, you can learn about setting up Open5Gs NRF in this post, and keep tuned for a lot more content on 5GC!

The Surprisingly Complicated World of SMS: Special Characters

SMS by default uses the GSM-7 bit alphabet, thanks to the fact each letter is only 7 bits long, this means you can cram 160 characters into a 140 byte message body.

However, this 7-bit alphabet is, well, limited, because it’s 7 bits long it means we can only have 128 different combinations of these bits, or to put it another way, with only 128 different unique combinations of these bits, we can only define 128 characters.

You have the standard 26 latin alphabet characters that Sesame Street drilled into you, some characters with accents, digits, and a limited set of symbols.

The GSM 7 bit alphabet does not include is character sets and symbols common for non-English written languages.

Shift Tables

To deal with this 3GPP introduced “National Language Shift Tables”, which are enable a sort of find-and-replace approach to the 7-bit alphabet, where certain characters that are unused in one alphabet, take the value of characters from the local alphabet.

So if you want to send the character Ğ (Found in the Turkish and Azerbaijani alphabets) you’d select the Turkish language Shift table, that replaces the capital G (71) with Ğ.

Of course you need to have two things to do this, you need the Language Shift Table to tell you what local-language letters replace what default letters, and a mechanism to state that you’re using a language shift table.

3GPP define the National Language Shift tables in TS 23.038, where you can lookup the character you want to encode, so you know what 7 bit value it uses, for example our character Ğ is 1000111 in the 7-bit alphabet.

Next we need to indicate that we don’t want 1000111 in the 7-bit alphabet to be rendered as “G”, we want to use the “Turkish National Language Single Shift Table” which will render it as “Ğ”. We do this in the User Data Header of the SMS Body, the same way we’d indicate that an SMS is a concatenated SMS.

But by adding a header in the User Data Header of the SMS Body, we eat into the space we can use to send the message body, with a single User Data Header indicating that the Turkish National Language Single Shift Table is being used, we go from a maximum of 160 characters without the User Data Header, to 134 characters.

I’ve shared a lot more information on the User Data Header in this post on Concatenated SMS, should you be interested.

UCS2 Encoding

So that’s all well and good for other languages that have some overlap in letters, where we can substitute “G” for “Ğ”, but Unicode have 3304 emojis defined at the time of writing.

No matter how many shift tables you define, you’re not going to cover all of these in a 7-bit alphabet.

So all this encoding falls to 💩 when someone adds an Emoji.

The “😀” Emoji, represented as U+1F600 in Unicode, can be encoded as 0xF09F9880 in UTF-8 or 0xD83DDE00 in UTF-16.

So in 3GPP Networks, when you need more than 128 characters to work with, and when shift tables won’t cut the mustard, you can change the encoding used to use the International Standards Organisations’ “Universal coded character set 2” (UCS-2).

Unfortunately UCS-2 never really took off, but luckily it overlaps with UTF-16 character set, which is a lot more common.

So if you’ve got a “😀” Emoji in your SMS body the encoding of the message will be changed from GSM-7 to use a different encoding -UTF-16 / UCS2.

SMS Body showing TP-DCS character set is UCS2 / UTF-16 as Emojis are present

There’s a catch here, if you’re moving from a 7-bit alphabet to a 16 bit alphabet, you’re going to have a lot less space to work with.

A single SMS contains 1120 bits for the user data (The actual message).

With GSM-7 bit encoding, each letter takes up 7 bits, so 1120÷7 gives us 160 characters.

With UTF-16/UCS2 encoding, each letter takes up 16 bits so 1120÷16 only give us 70 characters.

So what happens next?

Often when Emojis are used, as our message is now limited to 70 characters concatenated messages are used, which takes a further 8 bytes of our message body if concatenated messages are used, further limiting the message length.

Backing up and Restoring Open5GS

You may find you need to move your Open5GS deployments from one server to another, or split them between servers.
This post covers the basics of migrating Open5GS config and data between servers by backing up and restoring it elsewhere.

The Database

Open5GS uses MongoDB as the database for the HSS and PCRF. This database contains all our SDM data, like our SIM Keys, Subscriber profiles, PCC Rules, etc.

Backup Database

To backup the MongoDB database run the below command (It doesn’t need sudo / root to run):

mongodump -o Open5Gs_"`date +"%d-%m-%Y"`"

You should get a directory called Open5Gs_todaysdate, the files in that directory are the output of the MongoDB database.

Restore Database

If you copy the backup we just took (the directory named Open5Gs_todaysdate) to the new server, you can restore the complete database by running:

mongorestore Open5Gs_todaysdate

This restores everything in the database, including profiles and user accounts for the WebUI,

You may instead just restore the Subscribers table, leaving the Profiles and Accounts unchanged with:

mongorestore Open5Gs_todaysdate/open5gs/subscribers.bson -c subscribers -d open5gs

The database schema used by Open5GS changed earlier this year, meaning you cannot migrate directly from an old database to a new one without first making a few changes.

To see if your database is affected run:

mongo open5gs --eval 'db.subscribers.find({"__v" : 0}).toArray()' | grep "imsi" | wc -l

Which will let you know how many subscribers are using the old database type. If it’s anything other than 0 running this Python script will update the database as required.

Once you have installed Open5GS onto the new server you’ll need to backup the data from the old one, and restore it onto the new one.

The Config Files

The text based config files define how Open5Gs will behave, everything from IP Addresses to bind on, to the interfaces and PLMN.

Again, you’ll need to copy them from the old server to the new, and update any IP Addresses that may change between the two.

On the old server run:

cp -r /etc/open5gs /tmp/

Then copy the “open5gs” folder to the new server into the /etc/ directory.

If you’re also changing the IP Address you’re binding on, you’ll need to update that in the YAML files.

Bringing Everything Online

Finally you’ll need to restart all the services,

sudo systemctl start open5gs-*

Run a basic health check to ensure the services are running,

ps aux | grep open5gs-

Should list all the running Open5Gs services,

And then check the logs to ensure everything is working as expected,

tail -f /var/log/open5gs/*.log

GTP Extension Headers (PDU session user plane protocol) in 5GC

The GPRS Tunneling Protocol is one of the last common bits of signaling seen in 5G networks, having existed since GPRS was standardized in 1998, and 23 years later, it’s still in use on the user plane.

But networks evolve, and 5G Networks required some extensions to GTP to support these on the N9 and N3 reference points. (UPF to UPF and UPF to gNodeB / Access Network).

3GPP TS 38.415 outlines the PDU session user plane protocol used in 5GC.

The Need for GTP Header Extensions

As increasingly complex QoS capabilities are introduced into 5GC, there is a need to signal certain information on a per-packet basis.

In previous generations of mobile network, traffic could be differentiated with different Tunnel Endpoint Identifiers (TEIDs) but not on a per-packet basis,

The expansion of QoS in 5GC means the UPF of gNodeB may need to set the QoS Flow Identifier per-packet, include delay measurements or signal that Reflective QoS is being used per packet, for this, you need to extend GTP.

Fortunately GTP has support for Extension Headers and this has been leveraged to add the PDU Session Container in the Extension Header of a GTP packet.

In here you can set on a per packet basis:

  • QoS Flow Identifier (QFI) – Used to identify the QoS flow to be used (Pretty self explanatory)
  • Reflective QoS Indicator (RQI) – To indicate reflective QoS is supported for the encapsulated packet
  • Paging Policy Presence (PPP) – To indicate support for Paging Policy Indicator (PPI)
  • Paging Policy Indicator (PPI) – Sets parameters of paging policy differentiation to be applied
  • QoS Monitoring Packet – Indicates packet is used for QoS Monitoring and DL & UL Timestamps to come
  • UL/DL Sending Time Stamps – 64 bit timestamp generated at the time the UPF or UE encodes the packet
  • UL/DL Received Time Stamps – 64 bit timestamp generated at the time the UPF or UE received the packet
  • UL/DL Delay Indicators – Indicates Delay Results to come
  • UL/DL Delay Results – Delay measurement results
  • Sequence Number Presence – Indicates if QFI sequence number to come
  • UL/DL QFI Sequence Number – Sequence number as assigned by the UPF or gNodeB

The Surprisingly Complicated World of SMS: Concatenated / Multipart SMS

Most people think of 160 characters as the length of an SMS. But the payload is actually 140 bytes, but with better encoding 1 character doesn’t require 1 byte.

The above paragraph is exactly 160 characters. It would fit into a standard SMS.

By using the GSM 7 bit alphabet, you can cram 16 characters into 140 bytes (octets) of space, which is kind of cool.

140 bytes of data containing 160 characters of text

But people often need to convey more text than just 160 characters, or if you’re using characters that don’t exist in the GSM 7-bit alphabet, that limit becomes even less than 160 characters (different encodings other than GSM-7 need more data to transfer the same number of characters) so we get into multipart SMS, another feature in the surprisingly complicated world of SMS.

You’d think if you took a 160 character SMS, and concatenated it onto another 160 character SMS, you’d get a total of 320 characters, right (160+160=320)?
Alas it’s not that simple.

In order to achieve the concatenation of messages in a way that’s transparent to the users (rather than a series of SMSes coming through one-after-the-ther) a User-Data Header (TP-User-Data-Header-Indicator aka TP-UHDI) is added to the TP-User Data of the TPDU (the part that actually contains the user message).

This User-Data Header takes up 7 bytes, which with GSM encoding robs us of 6 characters from the message length. (Not a typo, GSM7 encoding does not mean 1 character = 1 byte, hence we can get 160 characters into 140 bytes of space)
So a two SMS concatenated message would only allow 268 characters to be sent (134 characters + 134 characters).

Let’s take a look at this header that’s robbing us of message length, but enabling us to concatenate messages.

For starters, the information about how many parts in the concatenated message, and what part number this one is, is located in the message body, hence robbing us of characters.

But we only know about the presence of this header being in the message body because the SMS-SUBMIT TPDU has the TP-UDHI flag (TP-User-Data-Header-Indicator) set, so we know the User Data is prefixed with the User-Data-Header.

Now if we have a look in the TP-User-Data we can see the User-Data Header, this can actually carry a few different payloads, but in our case, it’s carrying the Concatenated Short Messages IE, which tells us the message identifier (unique per single-but-multi-part message, the number of parts in the message (in this case 2) and the part number this is (part 1 of 2).

First part of a two part SMS

Now the phone has indicated this is a multipart message, the length of the data is still 160, but the length of the actual message is now limited to 134 characters with GSM7 encoding.

The encoding isn’t as bad as you might expect:
1st byte indicates the total length of the User Data Headers (After this the actual user data begins),
2nd byte is the IE identifier, for Concatenated Short Messages, this is 00,
3rd byte is the length of the Concatenated Short Messages IE,
4th byte is the message identifier in hex,
5th byte is the number of message parts in hex (So up to 255 message parts)
6th byte is the message part number, to aid in putting it back together in order.

3GPP TS 23.040 – 9.2.3.24 TP-User Data (TP-UD) – Encoding of User Data Header and generic IE
Concatenated short message IE encoding

So what we end up with is a header inside our user payload, advising that this is a concatenated SMS, the message identifier, the number of parts in the message, and the part number of this particular message.

Last part of two part SMS

The SMSc on receipt of these has to spool them back out to the destination with the same message part number, and same headers in place.

The phone receiving the SMS has to wait for all the parts to come through and then reassemble before rendering to the user.

So that’s how concatenated SMS works. While this may seem convoluted and silly in a world where transfering more than 140 bytes of data is trivial, SMS was introduced in the early 1990s, and in theory at least, a user with a phone that supported SMS purchased when SMS was introduced, should still be able to interwork with phones today.

Framed Routing in 5G

Previous generations of core mobile network, would only allocate a single IP address per UE (Well, two if dual-stack IPv4/IPv6 if you want to be technical). But one of the cool features in 5GC is the support for Framed Routing natively.

You could do this on several EPC platforms on LTE, but it’s support was always a bit shoe-horned in, and the UE was not informed of the framed addresses.

If you’ve worked in a wireline ISP you’re probably familiar with the concept of framed routing already, in short it’s one or more static routes, typically returned from a AAA server (Normally RADIUS) that are then routed to the subscriber.

Each subscriber gets allocated an IP by the network, but other IPs can also be routed to the subscriber, based on the network and CIDR mask.

So let’s say we allocate a public IP of 1.2.3.4/32 to our subscriber, but our subscriber is a fixed-wireless user running a business and they want a extra public IP Addresses.

How do we do this? With Framed Routing.

Now in our UDM we can add a “Framed IP”, and when the SMF sets up a session for our subscriber, the extra networks specified in the framed routes will get routed to that UE.

If we add 203.176.196.0/30 in our UDM for a subscriber, when the subscriber attaches the UPF will be setup to forward traffic to 1.2.3.4/32 and also traffic to 203.176.196.0/30 to the UE.

Update: I previously claimed:
Best of all this is signaled to the UE during the attach, so the UE is say a router, it becomes aware of the Framed IPs allocated to it.
This is incorrect! Thanks to Anonymous Telco Engineer from an Anonymous Nordic Country for pointing this out, it is not signaled to the UE.

More info in 3GPP TS 23.501 section 5.6.14 Support of Framed Routing.

Reflective QoS in 5G

Reflective QoS is a clever new concept introduced in 5G SA networks.

The concept is rather simple, apply QoS in the downlink, and let the UE reply using the QoS in the uplink.

So what is Reflective QoS?
If I send an ICMP ping request to a UE with a particular QoS Flow setup on the downlink, if Reflective QoS is enabled, the ICMP reply will have the same QoS applied on the uplink. Simple as that.

The UE looks at the QoS applied on the downlink traffic, and applies the same to the uplink traffic.

Let’s take another example, if a user starts playing an online game, and the traffic to the user (Downlink) has certain QoS parameters set, if Reflective QoS is enabled, the UE builds rules based on the incoming traffic based on the source IP / port / protocol of the traffic received, and the QoS used on the downlink, and applies the same on the uplink.

But actually getting Reflective QoS enabled requires a few more steps…

Reflective QoS is enabled on a per-packet basis, and is indicated by the UPF setting the Reflective QoS Indication (RQI) bit in the encapsulation header next to the QFI (This is set in the GTP header, as an extension header, used on the N3 and N9 reference points).

But before this is honored, a few other parameters have to be setup.

  • A Reflective QoS Timer (RQ Timer) has to be set, this can be done during the PDU Session Establishment, PDU Session Modification procedure, or set to a default value.
  • SMF has to set Reflective QoS Attribute (RQA) on the QoS profile for this traffic on the N2 reference point towards gNodeB
  • SMF must instruct UPF to use uplink reflective QoS by generating a new UL PDR for this SDF via the N4 reference point

When these requirements have been met, the traffic from the UPF to the gNodeB (N3 reference point) has the Reflective QoS Indication (RQI) bit in the encapsulation header, which is encapsulated and signaled down to the UE, which builds a rule based on the received IP source / port / protocol, and sends responses using the same QoS attributes.

N20 5G SBI for Nsmsf for SMS over 5GC

SMS in 5GC

Like in EPS / LTE, there are two ways to send SMS in Standalone 5G Core networks.

SMS over IMS or SMS over NAS – Both can be used on the same network, or just one, depending on operator preferences.

SMS over IMS in 5G

SMS over IMS uses the IMS network to send SMS. SIP MESSAGE methods are used to deliver SMS between users. While most operators have deployed IMS for 4G/LTE subscribers to use VoLTE some time ago, there are some changes required to the IMS architecture to support VoNR (Voice over New Radio) on the carrier side, and support for VoNR in commercial devices is currently in its early stages. Because of this many 5G devices and networks do not yet support SMS over IMS.

I’ve read in some places that RCS – The GSMA’s Rich Communications Service will replace SMS in 5GC. If this is the case, it reflected in any of the 3GPP standards.

SMS over NAS

To make a voice call on a device or network that does not support VoNR, EPS (VoLTE) fallback is used.
This means when making or receiving a call, the UE drops from the 5G RAN to using a 4G (LTE) basd RAN, and then uses VoLTE to make the call the same as it would when connected to 4G (LTE) networks, because it is connected to a 4G network.
This works technically, but is not the prefered option as it adds extra signaling and complexity to the network, and delays in the call setup, and it’s expected operators will eventually move to VoNR,but works as a stop-gap measure.

But mobile networks see a lot of SMS traffic. If every time an SMS was sent the UE had to rely on EPS fallback to access IMS, this would see users ping-ponging between 4G and 5G every time they sent or received an SMS.

This isn’t a new problem, in fact SMS-over-NAS was initially added to 4G (LTE) to allow devices to stay connected to the EPC (4G Core network) but still send and receive SMS, even if the network or device relied on “Circuit-Switched fallback” (A mechanism to drop from 4G to 2G / 3G for voice calls).

5GC reintroduces the SMS-over-NAS feature, allowing the SMS messages to be carried over NAS messaging on the N1 interface. Voice calls may still require fallback to EPS (4G) to make calls over VoLTE, but SMS can be carried over NAS messaging, minimizing the amount of Inter-RAT handovers required.

The Nsmsf_SMService

For this a new Service Based Interface is introduced between the AMF and the SMSF (SMS Function, typically built into an SMSc), via the N20 / Nsmsf SBI to offer the Nsmsf_SMService service.

There are 3 operations supported for the Nsmsf_SMService:

  • Active – Initiated by the AMF – Used to active the SMS service for a given subscriber,
  • Deactivate – Initiated by the AMF – Used to deactivate the SMS over NAS service for a given subscriber.
  • UplinkSMS – Initiated by the AMF to transfer the SMS payload towards the SMSF.

The UplinkSMS is a HTTP post from the AMF with the SUPI in the Request URI and the request body containing a JSON encoded SmsRecordData.

Astute readers may notice that’s all well and good, but that only covers Mobile Originated (MO) SMS, what about Mobile Terminated (MT) SMS?

Well that’s actually handled by a totally different SBI, the Namf_Communication action “N1N2MessageTransfer” is resused for sending MT SMS, as that interface already exists for use by SMF, LMF and PCF, and 5GC attempts to reuse interfaces as much as possible.

5G Online Charging with the Nchf_ConvergedCharging SBI

There’s no such thing as a free lunch, and 5G is the same – services running through a 5G Standalone core need to be billed.

In 5G Core Networks, the SMF (Session Management Function) reaches out to the CHF (Charging Function) to perform online charging, via the Nchf_ConvergedCharging Service Based Interface (aka reference point).

Like in other generations of core mobile networks, Credit Control in 5G networks is based on 3 functions:
Requesting a quota for a subscriber from an online charging service, which if granted permits the subscriber to use a certain number of units (in this case data transferred in/out).
Just before those units are exhausted sending an update to request more units from the online charging service to allow the service to continue.
When the session has ended or or subscriber has disconnected, a termination to inform the online charging service to stop billing and refund any unused credit / units (data).

Initial Service Creation (ConvergedCharging_Create)

When the SMF needs to setup a session, (For example when the AMF sends the SMF a Nsmf_PDU_SessionCreate request), the CTF (Charging Trigger Function) built into the SMF sends a Nchf_ ConvergedCharging_Create (Initial, Quota Requested) to the Charging Function (CHF).

Because the Nchf_ConvergedCharging interface is a Service Based Interface this is carried over HTTP, in practice, this means the SMF sends a HTTP post to http://yourchargingfunction/Nchf_ConvergedCharging/v1/chargingdata/

Obviously there’s some additional information to be shared rather than just a HTTP post, so the HTTP post includes the ChargingDataRequest as the Request Body. If you’ve dealt with Diameter Credit Control you may be expecting the ChargingDataRequest information to be a huge jumble of nested AVPs, but it’s actually a fairly short list:

  • The subscriberIdentifier (SUPI) is included to identify the subscriber so the CHF knows which subscriber to charge
  • The nfConsumerIdentification identifies the SMF generating the request (The SBI Consumer)
  • The invocationTimeStamp and invocationSequenceNumber are both pretty self explanatory; the time the request is sent and the sequence number from the SBI consumer
  • The notifyUri identifies which URI should receive subsequent notifications from the CHF (For example if the CHF wants to terminate the session, the SMF to send that to)
  • The multipleUnitUsage defines the service-specific parameters for the quota being requested.
  • The triggers identifies the events that trigger the request

Of those each of the fields should be pretty self explanatory as to their purpose.
The multipleUnitUsage data is used like the Service Information AVP in Diameter based Credit Control, in that it defines the specifics of the service we’re requesting a quota for. Inside it contains a mandatory ratingGroup specifying which rating group the CHF should use, and optionally requestedUnit which can define either the amount of service units being requested (For us this is data in/out), or to tell the CHF units are needed. Typically this is used to define the amount of units to be requested.

On the amount of units requested we have a bit of a chicken-and-egg scenario; we don’t know how many units (In our case the units is transferred data in/out) to request, if we request too much we’ll take up all the customer’s credit, potentially prohibiting them from accessing other services, and not enough requested and we’ll constantly slam the CHF with requests for more credit.
In practice this value is somewhere between the two, and will vary quite a bit.

Based on the service details the SMF has put in the Nchf_ ConvergedCharging_Create request, the Charging Function (CHF) takes into account the subscriber’s current balance, credit control policies, etc, and uses this to determine if the Subscriber has the required balances to be granted a service, and if so, sends back a 201 CREATED response back to the Nchf_ConvergedCharging_Create request sent by the CTF inside the SMF.

This 201 CREATED response is again fairly clean and simple, the key information is in the multipleQuotaInformation which is nested within the ChargingDataResponse, which contains the finalUnitIndication defining the maximum units to be granted for the session, and the triggers to define when to check in with CHF again, for time, volume and quota thresholds.

And with that, the service is granted, the SMF can instruct the UPF to start allowing traffic through.

Update (ConvergedCharging_Update)

Once the granted units / quota has been exhausted, the Update (ConvergedCharging_Update) request is used for requesting subsequent usage / quota units. For example our Subscriber has used up all the data initially allocated but is still consuming data, so the SMF sends a Nchf_ConvergedCharging_Update request to request more units, via another HTTP post, to the CHF, with the requested service unit in the request body in the form of ChargingDataRequest as we saw in the initial ConvergedCharging_Create.

If the subscriber still has credit and the CHF is OK to allow their service to continue, the CHF returns a 200 OK with the ChargingDataResponse, again, detailing the units to be granted.

This procedure repeats over and over as the subscriber uses their allocated units.

Release (ConvergedCharging_Release)

Eventually when our subscriber disconnects, the SMF will generate a Nchf_ConvergedCharging_Release request, detailing the data the subscriber used in the ChargingDataRequest in the body, to the CHF, so it can refund any unused credits.

The CHF sends back a 204 No Content response, and the procedure is completed.

More Info

If you’ve had experience in Diameter credit control, this simple procedure will be a breath of fresh air, it’s clean and easy to comprehend,
If you’d like to learn more the 3GPP specification docs on the topic are clear and comprehensible, I’d suggest:

  • TS 132 290 – Short overview of charging mechanisms
  • TS 132 291 – Specifics of the Nchf_ConvergedCharging interface
  • The common 3GPP charging architecture is specified in TS 32.240
  • TS 132 291 – Overview of components and SBIs inc Operations

Jaffa Cakes explain the nuances between Centralized vs Decentralized Online Charging in 3GPP Networks

While reading through the 3GPP docs regarding Online Charging, there’s a concept that can be a tad confusing, and that’s the difference between Centralized and Non-Centralized Charging architectures.

The overall purpose of online charging is to answer that deceptively simple question of “does the user have enough credit for this action?”.

In order to answer that question, we need to perform rating and unit determination.

Rating

Rating is just converting connectivity credit units into monetary units.

If you go to the supermarket and they have boxes of Jaffa Cakes at $2.50 each, they have rated a box of Jaffa Cakes at $2.50.

1 Box of Jaffa Cakes rated at $2.50 per box

In a non-snack-cake context, such as 3GPP Online Charging, then we might be talking about data services, for example $1 per GB is a rate for data.
Or for a voice calls a cost per minute to call a destination, such as is $0.20 per minute for a local call.

Rating is just working out the cost per connectivity unit (Data or Minutes) into a monetary cost, based on the tariff to be applied to that subscriber.

Unit Determination

The other key piece of information we need is the unit determination which is the calculation of the number of non-monetary units the OCS will offer prior to starting a service, or during a service.

This is done after rating so we can take the amount of credit available to the subscriber and calculate the number of non-monetary units to be offered.

Converting Hard-Currency into Soft-Snacks

In our rating example we rated a box of Jaffa Cakes at $2.50 per box. If I have $10 I can go to the shops and buy 4x boxes of Jaffa cakes at $2.50 per box. The cashier will perform unit determination and determine that at $2.50 per box and my $10, I can have 4 boxes of Jaffa cakes.

Again, steering away from the metaphor of the hungry author, Unit Determination in a 3GPP context could be determining how many minutes of talk time to be granted.
Question: At $0.20 per minute to a destination, for a subscriber with a current credit of $20, how many minutes of talk time should they be granted?
Answer: 100 minutes ($20 divided by $0.20 per minute is 100 minutes).

Or to put this in a data perspective,
Question: Subscriber has $10 in Credit and data is rated at $1 per GB. How many GB of data should the subscriber be allowed to use?
Answer: 10GB.

Putting this Together

So now we understand rating (working out the conversion of connectivity units into monetary units) and unit determination (determining the number of non-monetary units to be granted for a given resource), let’s look at the the Centralized and Decentralized Online Charging.

Centralized Rating

In Centralized Rating the CTF (Our P-GW or S-CSCF) only talk about non-monetary units.
There’s no talk of money, just of the connectivity units used.

The CTFs don’t know the rating information, they have no idea how much 1GB of data costs to transfer in terms of $$$.

For the CTF in the P-GW/PCEF this means it talks to the OCS in terms of data units (data In/out), not money.

For the CTF in the S-CSCF this means it only ever talks to the OCS in voice units (minutes of talk time), not money.

This means our rates only need to exist in the OCS, not in the CTF in the other network elements. They just talk about units they need.

De-Centralized Rating

In De-Centralized Rating the CTF performs the unit conversion from money into connectivity units.
This means the OCS and CTF talk about Money, with the CTF determining from that amount of money granted, what the subscriber can do with that money.

This means the CTF in the S-CSCF needs to have a rating table for all the destinations to determine the cost per minute for a call to a destination.

And the CTF in the P-GW/PCEF has to know the cost per octet transferred across the network for the subscriber.

In previous generations of mobile networks it may have been desirable to perform decentralized rating, as you can spread the load of calculating our the pricing, however today Centralized is the most common way to approach this, as ensuring the correct rates are in each network element is a headache.

Centralized Unit Determination

In Centralized Unit Determination the CTF tells the OCS the type of service in the Credit Control Request (Requested Service Units), and the OCS determines the number of non-monetary units of a certain service the subscriber can consume.

The CTF doesn’t request a value, just tells the OCS the service being requested and subscriber, and the OCS works out the values.

For example, the S-CSCF specifies in the Credit Control Request the destination the caller wishes to reach, and the OCS replies with the amount of talk time it will grant.

Or for a subscriber wishing to use data, the P-GW/PCEF sends a Credit Control Request specifying the service is data, and the OCS responds with how much data the subscriber is entitled to use.

De-Centralized Unit Determination

In De-Centralized Unit Determination, the CTF determines how many units are required to start the service, and requests these units from the OCS in the Credit Control Request.

For a data service,the CTF in the P-GW would determine how many data units it is requesting for a subscriber, and then request that many units from the OCS.

For a voice call a S-CSCF may request an initial call duration, of say 5 minutes, from the OCS. So it provides the information about the destination and the request for 300 seconds of talk time.

Session Charging with Unit Reservation (SCUR)

Arguably the most common online charging scenario is Session Charging with Unit Reservation (SCUR).

SCUR relies on reserving an amount of funds from the subscriber’s balance, so no other services can those funds and translating that into connectivity units (minutes of talk time or data in/out based on the Requested Session Unit) at the start of the session, and then subsequent requests to debit the reserved amount and reserve a new amount, until all the credit is used.

This uses centralized Unit Determination and centralized Rating.

Let’s take a look at how this would look for the CTF in a P-GW/PCEF performing online charging for a subscriber wishing to use data:

  1. Session Request: The subscriber has attached to the network and is requesting service.
  2. The CTF built into the P-GW/PCEF sends a Credit Control Request: Initial Request (As this subscriber has just attached) to the OCS, with Requested Service Units (RSU) of data in/out to the OCS.
  3. The OCS performs rating and unit determination, and according to it’s credit risk policies, and a whole lot of other factors, comes back with an amount of data the subscriber can use, and reserves the amount from the account.
    (It’s worth noting at this point that this is not necessarily all of the subscriber’s credit in the form of data, just an amount the OCS is willing to allocate. More data can be requested once this allocated data is used up.)
  4. The OCS sends a Credit Control Answer back to our P-GW/PCEF. This contains the Granted Service Unit (GSU), in our case the GSU is data so defines much data up/down the user can transfer. It also may include a Validity Time (VT), which is the number of seconds the Credit Control Answer is valid for, after it’s expired another Credit Control Request must be sent by the CTF.
  5. Our P-GW/PCEF processes this, starts measuring the data used by the subscriber for reporting later, and sets a timer for the Validity Time to send another CCR at that point.
    At this stage, our subscriber is able to start using data.
  1. Some time later, either when all the data allocated in the Granted Service Units has been consumed, or when the Validity Time has expired, the CTF in the P-GW/PCEF sends another Credit Control Request: Update, and again includes the RSU (Requested Service Units) as data in/out, and also a USU (Used Service Units) specifying how much data the subscriber has used since the first Credit Control Answer.
  2. The OCS receives this information. It compares the Used Session Units to the Granted Session Units from earlier, and with this is able to determine how much data the subscriber has actually used, and therefore how much credit that equates to, and debit that amount from the account.
    With this information the OCS can reserve more funds and allocate another GSU (Granted Session Unit) if the subscriber has the required balance. If the subscriber only has a small amount of credit left the FUI (Final Unit Indication AVP) is set to determine this is all the subscriber has left in credit, and if this is exhausted to end the session, rather than sending another Credit Control Request.
  3. The Credit Control Answer with new GSU and the FUI is sent back to the P-GW/PCEF
  4. The P-GW/PCEF allows the session to continue, again monitoring used traffic against the GSU (Granted Session Units).
  1. Once the subscriber has used all the data in the Granted Session Units, and as the last CCA included the Final Unit Indicator, the CTF in the P-GW/PCEF knows it can’t just request more credit in the form of a CCR Update, so cuts of the subscribers’s session.
  2. The P-GW/PCEF then sends a Credit Control Request: Termination Request with the final Used Service Units to the OCS.
  3. The OCS debits the used service units from the subscriber’s balance, and refunds any unused credit reservation.
  4. The OCS sends back a Credit Control Answer which may include the CI value for Credit Information, to denote the cost information which may be passed to the subscriber if required.

Converting Elevation Data (DEM) for Forsk Atoll

After headaches importing elevation (DEM) data into Forsk Atoll, I found a better mechanism for converting them,

I’d been having issues with as soon as the elevation passed 255 meters, resetting to 0 in the PNG as it didn’t understand values beyond this.

I was able to open the elevation data in GlobalMapper (You can use the trial if required), then selecting Export -> Export Raster/Image Format,

Then select Erdas Image File

Set file type to Elevation 16-bit integer samples,

Now you should be able to import it straight into Atoll as your elevation data.

EIR in 5G Networks (N5g-eir_EquipmentIdentityCheck)

Today, we’re going to look at one of the simplest Service Based Interfaces in the 5G Core, the Equipment Identity Register (EIR).

The purpose of the EIR is very simple – When a subscriber connects to the network it’s Permanent Equipment Identifier (PEI) can be queried against an EIR to determine if that device should be allowed onto the network or not.

The PEI is the IMEI of a phone / device, with the idea being that stolen phones IMEIs are added to a forbidden list on the EIR, and prohibited from connecting to the network, making them useless, in turn making stolen phones harder to resell, deterring mobile phone theft.

In reality these forbidden-lists are typically either country specific or carrier specific, meaning if the phone is used in a different country, or in some cases a different carrier, the phone’s IMEI is not in the forbidden-list of the overseas operator and can be freely used.

The dialog goes something like this:

AMF: Hey EIR, can PEI 49-015420-323751-8 connect to the network?
EIR: (checks if 49-015420-323751-8 in forbidden list - It's not) Yes.

or

AMF: Hey EIR, can PEI 58-241992-991142-3 connect to the network?
EIR: (checks if 58-241992-991142-3 is in forbidden list - It is) No.

(Optionally the SUPI can be included in the query as well, to lock an IMSI to an IMEI, which is a requirement in some jurisdictions)

As we saw in the above script, the AMF queries the EIR using the N5g-eir_EquipmentIdentityCheck service.

The N5g-eir_EquipmentIdentityCheck service only offers one operation – CheckEquipmentIdentity.

It’s called by sending an HTTP GET to:

http://{apiRoot}/n5g-eir-eic/v1/equipment-status

Obviously we’ll need to include the PEI (IMEI) in the HTTP GET, which means if you remember back to basic HTTP GET, you may remember means you have to add ?attribute=value&attribute=value… for each attribute / value you want to share.

For the CheckEquipmentIdentity operation, the PEI is a mandatory parameter, and optionally the SUPI can be included, this means to query our PEI (The IMSI of the phone) against our EIR we’d simply send an HTTP GET to:

AMF: HTTP GET http://{apiRoot}/n5g-eir-eic/v1/equipment-status?pei=490154203237518
EIR: 200 (Body EirResponseData: status "WHITELISTED")

And how it would look for a blacklisted IMEI:

AMF: HTTP GET http://{apiRoot}/n5g-eir-eic/v1/equipment-status?pei=490154203237518
EIR: 404 (Body EirResponseData: status "BLACKLISTED")

Because it’s so simple, the N5g-eir_EquipmentIdentityCheck service is a great starting point for learning about 5G’s Service Based Interfaces.

You can find all the specifics in 3GPP TS 29.511 – Equipment Identity Register Services; Stage 3

Credit Control Request / Answer call flow in IMS Charging

Basics of EPC/LTE Online Charging (OCS)

Early on as subscriber trunk dialing and automated time-based charging was introduced to phone networks, engineers were faced with a problem from Payphones.

Previously a call had been a fixed price, once the caller put in their coins, if they put in enough coins, they could dial and stay on the line as long as they wanted.

But as the length of calls began to be metered, it means if I put $3 of coins into the payphone, and make a call to a destination that costs $1 per minute, then I should only be allowed to have a 3 minute long phone call, and the call should be cutoff before the 4th minute, as I would have used all my available credit.

Conversely if I put $3 into the Payphone and only call a $1 per minute destination for 2 minutes, I should get $1 refunded at the end of my call.

We see the exact same problem with prepaid subscribers on IMS Networks, and it’s solved in much the same way.

In LTE/EPC Networks, Diameter is used for all our credit control, with all online charging based on the Ro interface. So let’s take a look at how this works and what goes on.

Generic 3GPP Online Charging Architecture

3GPP defines a generic 3GPP Online charging architecture, that’s used by IMS for Credit Control of prepaid subscribers, but also for prepaid metering of data usage, other volume based flows, as well as event-based charging like SMS and MMS.

Network functions that handle chargeable services (like the data transferred through a P-GW or calls through a S-CSCF) contain a Charging Trigger Function (CTF) (While reading the specifications, you may be left thinking that the Charging Trigger Function is a separate entity, but more often than not, the CTF is built into the network element as an interface).

The CTF is a Diameter application that generates requests to the Online Charging Function (OCF) to be granted resources for the session / call / data flow, the subscriber wants to use, prior to granting them the service.

So network elements that need to charge for services in realtime contain a Charging Trigger Function (CTF) which in turn talks to an Online Charging Function (OCF) which typically is part of an Online Charging System (AKA OCS).

For example when a subscriber turns on their phone and a GTP session is setup on the P-GW/PCEF, but before data is allowed to flow through it, a Diameter “Credit Control Request” is generated by the Charging Trigger Function (CTF) in the P-GW/PCEF, which is sent to our Online Charging Server (OCS).

The “Credit Control Answer” back from the OCS indicates the subscriber has the balance needed to use data services, and specifies how much data up and down the subscriber has been granted to use.

The P-GW/PCEF grants service to the subscriber for the specified amount of units, and the subscriber can start using data.

This is a simplified example – Decentralized vs Centralized Rating and Unit Determination enter into this, session reservation, etc.

The interface between our Charging Trigger Functions (CTF) and the Online Charging Functions (OCF), is the Ro interface, which is a Diameter based interface, and is common not just for online charging for data usage, IMS Credit Control, MMS, value added services, etc.

3GPP define a reference online-charging interface, the Ro interface, and all the application-specific interfaces, like the Gy for billing data usage, build on top of the Ro interface spec.

Basic Credit Control Request / Credit Control Answer Process

This example will look at a VoLTE call over IMS.

When a subscriber sends an INVITE, the Charging Trigger Function baked in our S-CSCF sends a Diameter “Credit Control Request” (CCR) to our Online Charging Function, with the type INITIAL, meaning this is the first CCR for this session.

The CCR contains the Service Information AVP. It’s this little AVP that is where the majority of the magic happens, as it defines what the service the subscriber is requesting. The main difference between the multitude of online charging interfaces in EPC networks, is just what the service the customer is requesting, and the specifics of that service.

For this example it’s a voice call, so this Service Information AVP contains a “IMS-Information” AVP. This AVP defines all the parameters for a IMS phone call to be online charged, for a voice call, this is the called-party, calling party, SDP (for differentiating between voice / video, etc.).

It’s the contents of this Service Information AVP the OCS uses to make decision on if service should be granted or not, and how many service units to be granted. (If Centralized Rating and Unit Determination is used, we’ll cover that in another post)
The actual logic, relating to this decision is typically based on the the rating and tariffing, credit control profiles, etc, and is outside the scope of the interface, but in short, the OCS will make a yes/no decision about if the subscriber should be granted access to the particular service, and if yes, then how many minutes / Bytes / Events should be granted.

In the received Credit Control Answer is received back from our OCS, and the Granted-Service-Unit AVP is analysed by the S-CSCF.
For a voice call, the service units will be time. This tells the S-CSCF how long the call can go on before the S-CSCF will need to send another Credit Control Request, for the purposes of this example we’ll imagine the returned value is 600 seconds / 10 minutes.

The S-CSCF will then grant service, the subscriber can start their voice call, and start the countdown of the time granted by the OCS.

As our chatty subscriber stays on their call, the S-CSCF approaches the limit of the Granted Service units from the OCS (Say 500 seconds used of the 600 seconds granted).
Before this limit is reached the S-CSCF’s CTF function sends another Credit Control Request with the type UPDATE_REQUEST. This allows the OCS to analyse the remaining balance of the subscriber and policies to tell the S-CSCF how long the call can continue to proceed for in the form of granted service units returned in the Credit Control Answer, which for our example can be 300 seconds.

Eventually, and before the second lot of granted units runs out, our subscriber ends the call, for a total talk time of 700 seconds.

But wait, the subscriber been granted 600 seconds for our INITIAL request, and a further 300 seconds in our UPDATE_REQUEST, for a total of 900 seconds, but the subscriber only used 700 seconds?

The S-CSCF sends a final Credit Control Request, this time with type TERMINATION_REQUEST and lets the OCS know via the Used-Service-Unit AVP, how many units the subscriber actually used (700 seconds), meaning the OCS will refund the balance for the gap of 200 seconds the subscriber didn’t use.

If this were the interface for online charging of data, we’d have the PS-Information AVP, or for online charging of SMS we’d have the SMS-Information, and so on.

The architecture and framework for how the charging works doesn’t change between a voice call, data traffic or messaging, just the particulars for the type of service we need to bill, as defined in the Service Information AVP, and the OCS making a decision on that based on if the subscriber should be granted service, and if yes, how many units of whatever type.

Open5GS without NAT

While most users of Open5GS EPC will use NAT on the UPF / P-GW-U but you don’t have to.

While you can do NAT on the machine that hosts the PGW-U / UPF, you may find you want to do the NAT somewhere else in the network, like on a router, or something specifically for CG-NAT, or you may want to provide public addresses to your UEs, either way the default config assumes you want NAT, and in this post, we’ll cover setting up Open5GS EPC / 5GC without NAT on the P-GW-U / UPF.

Before we get started on that, let’s keep in mind what’s going to happen if we don’t have NAT in place,

Traffic originating from users on our network (UEs / Subscribers) will have the from IP Address set to that of the UE IP Pool set on the SMF / P-GW-C, or statically in our HSS.

This will be the IP address that’s sent as the IP Source for all traffic from the UE if we don’t have NAT enabled in our Core, so all external networks will see that as the IP Address for our UEs / Subscribers.

The above example shows the flow of a packet from UE with IP Address 10.145.0.1 sending something to 1.1.1.1.

This is all well and good for traffic originating from our 4G/5G network, but what about traffic destined to our 4G/5G core?

Well, the traffic path is backwards. This means that our router, and external networks, need to know how to reach the subnet containing our UEs. This means we’ve got to add static routes to point to the IP Address of the UPF / P-GW-U, so it can encapsulate the traffic and get the GTP encapsulated traffic to the UE / Subscriber.

For our example packet destined for 1.1.1.1, as that is a globally routable IP (Not an internal IP) the router will need to perform NAT Translation, but for internal traffic within the network (On the router) the static route on the router should be able to route traffic to the UE Subnets to the UPF / P-GW-U’s IP Address, so it can encapsulate the traffic and get the GTP encapsulated traffic to the UE / Subscriber.

Setting up static routes on your router is going to be different on what you use, in my case I’m using a Mikrotik in my lab, so here’s a screenshot from that showing the static route point at my UPF/P-GW-U. I’ve got BGP setup to share routes around, so all the neighboring routers will also have this information about how to reach the subscriber.

Next up we’ve got to setup IPtables on the server itself running our UPF/P-GW-U, to route traffic addressed to the UE and encapsulate it.

sudo ip route add 10.145.0.0/24 dev ogstun
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
sudo iptables -A FORWARD -i ogstun -o osgtun -s 10.145.0.0/24 -d 0.0.0.0/0 -j ACCEPT

And that’s it, now traffic coming from UEs on our UPF/P-GW will leave the NIC with their source address set to the UE Address, and so long as your router is happily configured with those static routes, you’ll be set.

If you want access to the Internet, it then just becomes a matter of configuring traffic from that subnet on the router to be NATed out your external interface on the router, rather than performing the NAT on the machine.

In an upcoming post we’ll look at doing this with OSPF and BGP, so you don’t need to statically assign routes in your routers.

Diameter – Insert Subscriber Data Request / Response

While we’ve covered the Update Location Request / Response, where an MME is able to request subscriber data from the HSS, what about updating a subscriber’s profile when they’re already attached? If we’re just relying on the Update Location Request / Response dialog, the update to the subscriber’s profile would only happen when they re-attach.

We need a mechanism where the HSS can send the Request and the MME can send the response.

This is what the Insert Subscriber Data Request/Response is used for.

Let's imagine we want to allow a subscriber to access an additional APN, or change an AMBR values of an existing APN;

We'd send an Insert Subscriber Data Request from the HSS, to the MME, with the Subscription Data AVP populated with the additional APN the subscriber can now access.

Beyond just updating the Subscription Data, the Insert Subscriber Data Request/Response has a few other funky uses.

Through it the HSS can request the EPS Location information of a Subscriber, down to the TAC / eNB ID serving that subscriber. It’s not the same thing as the GMLC interfaces used for locating subscribers, but will wake Idle UEs to get their current serving eNB, if the Current Location Request is set in the IDR Flags.

But the most common use for the Insert-Subscriber-Data request is to modify the Subscription Profile, contained in the Subscription-Data AVP,

If the All-APN-Configurations-Included-Indicator is set in the AVP info, then all the existing AVPs will be replaced, if it’s not then everything specified is just updated.

The Insert Subscriber Data Request/Response is a bit novel compared to other S6a requests, in this case it’s initiated by the HSS to the MME (Like the Cancel Location Request), and used to update an existing value.

PS Data Off

Imagine a not-too distant future, one without flying cars – just one where 2G and 3G networks have been switched off.

And the imagine a teenage phone user, who has almost run out of their prepaid mobile data allocation, and so has switched mobile data off, or a roaming scenario where the user doesn’t want to get stung by an unexpectedly large bill.

In 2G/3G networks the Circuit Switched (Voice & SMS) traffic was separate to the Packet Switched (Mobile Data).

This allowed users to turn of mobile data (GPRS/HSDPA), etc, but still be able to receive phone calls and send SMS, etc.

With LTE, everything is packet switched, so turning off Mobile Data would cut off VoLTE connectivity, meaning users wouldn’t be able to make/recieve calls or SMS.

In 3GPP Release 14 (2017) 3GPP introduced the PS Data Off feature.

This feature is primarily implemented on the UE side, and simply blocks uplink user traffic from the UE, while leaving other background IP services, such as IMS/VoLTE and MMS, to continue working, even if mobile data is switched off.

The UE can signal to the core it is turning off PS Data, but it’s not required to, so as such from a core perspective you may not know if your subscriber has PS Data off or not – The default APN is still active and in the implementations I’ve tried, it still responds to ICMP Pings.

IMS Registration stays in place, SMS and MMS still work, just the UE just drops the requests from the applications on the device (In this case I’m testing with an Android device).

What’s interesting about this is that a user may still find themselves consuming data, even if data services are turned off. A good example of this would be push notifications, which are sent to the phone (Downlink data). The push notification will make it to the UE (or at least the TCP SYN), after all downlink services are not blocked, however the response (for example the SYN-ACK for TCP) will not be sent. Most TCP stacks when ignored, try again, so you’ll find that even if you have PS Data off, you may still use some of your downlink data allowance, although not much.

The SIM EF 3GPPPSDATAOFF defines the services allowed to continue flowing when PS Data is off, and the 3GPPPSDATAOFFservicelist EF lists which IMS services are allowed when PS Data is off.

Usually at this point, I’d include a packet capture and break down the flow of how this all looks in signaling, but when I run this in my lab, I can’t differentiate between a PS Data Off on the UE and just a regular bearer idle timeout… So have an irritating blinking screenshot instead…

Docker & BIND as an ENUM Playground

In the last we covered what ENUM is and how it works, so to take this into a more practical example, I thought I’d share the details of the ENUM server I’ve setup in my lab, and the Docker container I’ve bundled it into.

Inside the Docker container we’ll be running Bind – this post won’t teach you much about Bind, there’s already lots of good information on it elsewhere, but we will cover the parameters involved in setting up ENUM records (NAPTR) for E.164 addresses.

Getting the Environment up and Running

First we’ll need to setup our environment, I’ve published the images for the container to Dockerhub, but we’ll build it from the Dockerfile so you can edit the files and rebuild as you play around:

git clone https://github.com/nickvsnetworking/ENUM_Playground
cd ENUM_Playground
docker build --pull --rm -f "Dockerfile" -t enum:latest "."

systemd-resolve on Ubuntu binds to port 53 by default, which can lead to some headaches, so we’ll create a new network in Docker for this to run in, so it doesn’t conflict with anything else you may be running:

sudo docker network create --subnet=172.30.0.0/26 enum_playground

And now we’ll run the ENUM container in the enum_playground network and with the IP 172.30.0.2,

docker run -d --rm --name=enum --net=enum_playground --ip=172.30.0.2 enum

Ok, that’s the environment setup, let’s run some queries!

E.164 to SIP URI Resolution with ENUM

In our last post we covered the basics of formatting an E.164 number and querying a DNS server to get it’s call routing information.

Again we’re going to use Dig to query this information. In reality ENUM queries would be run by an endpoint, or software like FreeSWITCH or Kamailio (Spoiler alert, posts on ENUM handling in those coming later), but as we’re just playing Dig will work fine.

So let’s start by querying a single E.164 address, +61355500911

First we’ll reverse it and put full stops / periods between the numbers, to get 1.1.9.0.0.5.5.5.3.1.6

Next we’ll add the e164.arpa prefix, which is the global prefix for ENUM addresses, and presto, that’s what we’ll query – 1.1.9.0.0.5.5.5.3.1.6.e164.arpa

Lastly we’ll feed this into a Dig query against the IP of our container and of type NAPTR,

dig @172.30.0.2 -t naptr 1.1.9.0.0.5.5.5.3.1.6.e164.arpa

So what did you get back?

Well, if everything is working your output should look something like the output I’ve got below,

NAPTR results for queried ENUM Address

So how do we interpret this? Well let’s break it down,

The first part is the domain we queried, simple enough in this case,

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Next up is the TTL or expiry, in this case it’s 3600 seconds (1 hour), shorter periods allow for changes to propagate / be reflected more quickly but at the expense of more load as results can’t be cached for as long. The class (IN) represents Internet, which is the only class commonly used, even on internal systems.

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Then we have the type of record returned, in our case it’s a NAPTR record,

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

After that is the Order, this defines the order in which the rules are to be parsed. Lower numbers are processed first, if no matches then the next lowest, and so on until the highest number is reached, we’ll touch on this in more detail later in this post,

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

The Pref is the processing preference. This is very handy for load balancing, as we can split traffic between hosts with different preferences. We’ll cover this later in this post too.

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

The Flags represent the type of record we’re going to get, for most ENUM traffic this is going to be set to U, to denote a SIP URI with Regex, while the Service value we’ll be looking for will be “E2U+sip” service to identify SIP URIs to route calls to, but could be other values like Email addresses, IM Addresses or PSTN numbers, to be parsed by other applications.

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Lastly we’ve got the Regex part. Again not going to cover Regex as a whole, just the DNS particulars.

Everything between the first and second ! denotes what we’re searching for, while everything from the second ! to the last ! denotes what we replace it with.

In the below example that means we’re matching ^.* which means starting with (^) any character (.) zero or more times (*), which gets replaced with sip:[email protected],

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

How should this be treated?

For the first example, a call to the E.164 address of 61355500912 will be first formatted into a domain as per the ENUM requirements (1.1.9.0.0.5.5.5.3.1.6.e164.arpa) and then queried as a NAPTR record against the DNS server,

1.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Only a single record has been returned so we don’t need to worry about the Order or Preference, and the Regex matches anything and replaces it with the resulting SIP URI of sip:[email protected], which is where we’ll send our INVITE.

Under the Hood

Inside the Repo we cloned earlier, if you open the e164.arpa.db file, things will look somewhat familiar,

The record we just queried is the first example in the Bind config file,

; E.164 Address +61355500911 - Simple no replacement (Resolves all traffic to sip:[email protected])
1.1.9.0.0.5.5.5.3.1.6 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

The config file is just the domain, class, type, order, preference, flags, service and regex.

Astute readers may have noticed the trailing . which where we can put a replacement domain if Regex is not used, but it cannot be used in conjunction with Regex, so for all our work it’ll just be a single trailing . on each line.

You can (and probably should) change the values in the e164.arpa.db file as we go along to try everything out, you’ll just need to rebuild the container and restart it each time you make a change.

This post is going to focus on Bind, but the majority of modern DNS servers support NAPTR records, so you can use them for ENUM as well, for example I manage the DNS for this site thorough Cloudflare, and I’ve put a screenshot below of an example private ENUM address I’ve added into it.

Setting up a NAPTR record in Cloudflare DNS

Preference to Split Traffic between Servers

So with a firm understanding of a single record being returned, let’s look at how we can use ENUM to cleverly route traffic to multiple hosts.

If we have a pool of servers we may wish to evenly distribute all traffic across them, so that’s how E.164 address +61355500912 is setup – to route traffic evenly (50/50) across two servers.

Querying it with Dig provides the following result:

dig @172.30.0.2 -t naptr 2.1.9.0.0.5.5.5.3.1.6.e164.arpa
;; ANSWER SECTION:
2.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" . 2.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

So as the order value (10) is the same for both records, we can ignore it – there isn’t one value lower than the other.

We can see both records have a preference of 100, in practice, this means they each get 50% of the traffic. The formula for traffic distribution is pretty simple, each server gets the value of it’s preference, divided by the total of all the preferences,

So for server1 it’s preference is 100 and the total of all the preferences combined is 200, so it gets 100/200, which is equivalent to one half aka 50%.

We might have a scenario where we have 3 servers, but one is significantly more powerful than the others, so let’s look at giving more traffic to one server and less to others, this example gets a little more complex but should cement your understanding of how the preference works;

dig @172.30.0.2 -t naptr 3.1.9.0.0.5.5.5.3.1.6.e164.arpa
3.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" . 3.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 200 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .
3.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

So now 3 servers, again none have a lower order than the other, it’s set to 10 for them all so we can ignore the order,

Next we can see the total of all the priority values is 400,

Server 2 has a priority of 100 so it gets 100/400 total priority, or a quarter of all traffic. Server 1 has the same value, so also gets a quarter of all traffic,

Server 3 however has a priority of 200 so it gets 200/400, or to simplify half of all traffic.

The Bind config for this is:

; E.164 Address +61355500913 - More complex load balance between 3 hosts (25% server1, 25% server2, 50% server3)
3.1.9.0.0.5.5.5.3.1.6 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" . 3.1.9.0.0.5.5.5.3.1.6 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .
3.1.9.0.0.5.5.5.3.1.6 IN NAPTR 10 200 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Order for Failover

Primarily the purpose of the order is to enable wildcard routes (as we’ll see later) to be overwritten by more specific routes, but a secondary use in some implementations use Order as a way to list the preferences of the SIP URIs to route to. For example we could have two servers, one a primary and the other a standby, with the standby only to be used only if the primary SIP URI was not responding.

E.164 number +61355500914 is setup to return two SIP URIs,

dig @172.30.0.2 -t naptr 4.1.9.0.0.5.5.5.3.1.6.e164.arpa
;; ANSWER SECTION:
4.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" . 4.1.9.0.0.5.5.5.3.1.6.e164.arpa. 3600 IN NAPTR  20 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Our DNS client will first use the SIP URI sip:[email protected] as it has the lower order value (10), and if that fails, can try the entry with the next lowest order-value (20) which would be sip:[email protected].

The Bind config for this is:

; E.164 Address +61355500914 - Order example returning multiple SIP URIs to try for failover
4.1.9.0.0.5.5.5.3.1.6 IN NAPTR 10 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" . 4.1.9.0.0.5.5.5.3.1.6 IN NAPTR 20 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Wildcards

If we have a 1,000 number block, having to add 1000 individual records can be very tedious. Instead we can use wildcard matching (thanks to the fact we’ve reversed the E.164 address) to match ranges. For example if we have E.164 numbers from +61255501000 to +61255501999 we can add a wildcard entry to match the +61255501x prefix,

I’ve set this up already so let’s lookup the E.164 number +6125501234,

dig @172.30.0.2 -t naptr 4.3.2.1.0.5.5.5.2.1.6.e164.arpa
;; ANSWER SECTION:
4.3.2.1.0.5.5.5.2.1.6.e164.arpa. 3600 IN NAPTR  50 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

If you look up any other number starting with +6125501 you’ll get the same result, and here’s the Bind config for it:

; Wildcard E.164 Address +61255501* - Wildcard example for all destinations starting with E.164 prefix +61255501x to single destination (sip:[email protected])
; For example E.164 number +6125501234 will resolve to sip:[email protected]
*.1.0.5.5.5.2.1.6 IN NAPTR 100 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

The catch with this is they’re all pointing at the same SIP URI, so we can’t treat the calls differently based on the called number – This is where the Regex magic comes in.

We can use group matching to match a group and fill it in the dialed number into the SIP Request URI, for example:

!(^.*$)!sip:+1\[email protected]!

Will match the E.164 number requested and put it inside sip:[email protected]

The +61255502xxx prefix is setup for this, so if we query +61255502000 (or any other number between +61255502000 and +61255502999) we’ll get the regex query in the resulting record.

Keep in mind DNS doesn’t actually apply the Regex transformation, just shares it, and the client applies the transformation.

dig @172.30.0.2 -t naptr 0.0.0.2.0.5.5.5.2.1.6.e164.arpa
;; ANSWER SECTION:
0.0.0.2.0.5.5.5.2.1.6.e164.arpa. 3600 IN NAPTR  100 100 "u" "E2U+sip" "!(^.*$)!sip:+1\[email protected]!" .

And the corresponding Bind config:

; Wildcard example for all destinations starting with E.164 prefix +61255502x to regex filled destination
; For example a request to 61255502000 will return sip:[email protected])
*.2.0.5.5.5.2.1.6 IN NAPTR 100 100 "u" "E2U+sip" "!(^.*$)!sip:+1\\[email protected]!" .

One last thing to keep in mind, is that Wildcard priorities are of any length.
This means +612555021 would match as well as +6125550299999999999999. Typically terminating switches drop any superfluous digits, and NU those that are too short, but keep this in mind, that length is not taken into account.

Wildcard Priorities

So with our wildcards in place, what if we wanted to add an exception, for example one number in our 61255502xxx block of numbers gets ported to another carrier and needs to be routed elsewhere?

Easy, we just add another entry for that number being more specific and with a lower order than the wildcard, which is what’s setup for E.164 number +61255502345,

dig @172.30.0.2 -t naptr 5.4.3.2.0.5.5.5.2.1.6.e164.arpa
;; ANSWER SECTION:
5.4.3.2.0.5.5.5.2.1.6.e164.arpa. 3600 IN NAPTR  50 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

Which does not return the same result as the others that match the wildcard,

Bind config:

; Wildcard example for all destinations starting with E.164 prefix +61255502x to regex filled destination
; For example a request to +61255502000 will return sip:[email protected])
*.2.0.5.5.5.2.1.6 IN NAPTR 100 100 "u" "E2U+sip" "!(^.*$)!sip:+1\\[email protected]!" .

; More specific example with lower order than +6125550x wildcard for E.164 address +61255502345 will return sip:[email protected]
5.4.3.2.0.5.5.5.2.1.6 IN NAPTR 50 100 "u" "E2U+sip" "!^.*$!sip:[email protected]!" .

We can combine all of the tricks we’ve covered here, from statically defined entries, wildcards, regex replacement, multiple entries with multiple orders and preferences, to create really complex routing, using only DNS.

Summary & Next Steps

So by now hopefully you’ve got a fair understanding of how NAPTR and DNS work together to translate E.164 addresses into SIP URIs,

Of course being able to do this manually with Dig and comprehend how it’ll route is only one part of the picture, in the next posts we’ll cover using Kamailio and FreeSWITCH to query ENUM routing information and route traffic to it,