Category Archives: RFCs & Standards

GTPv2 – F-TEID Interface Types

I’ve been working on a ePDG for VoWiFi access to my IMS core.

This has led to a bit of a deep dive into GTP (easy enough) and GTPv2 (Bit harder).

The Fully Qualified Tunnel Endpoint Identifier includes an information element for the Interface Type, identified by a two digit number.

Here we see S2b is 32

In the end I found the answer in 3GPP TS 29.274, but thought I’d share it here.

0S1-U eNodeB GTP-U interface
1S1-U SGW GTP-U interface
2S12 RNC GTP-U interface
3S12 SGW GTP-U interface
4S5/S8 SGW GTP-U interface
5S5/S8 PGW GTP-U interface
6S5/S8 SGW GTP-C interface
7S5/S8 PGW GTP-C interface
8S5/S8 SGW PMIPv6 interface (the 32 bit GRE key is encoded in 32 bit TEID field and since alternate CoA is
not used the control plane and user plane addresses are the same for PMIPv6)
9S5/S8 PGW PMIPv6 interface (the 32 bit GRE key is encoded in 32 bit TEID field and the control plane and
user plane addresses are the same for PMIPv6)
10S11 MME GTP-C interface
11S11/S4 SGW GTP-C interface
12S10 MME GTP-C interface
13S3 MME GTP-C interface
14S3 SGSN GTP-C interface
15S4 SGSN GTP-U interface
16S4 SGW GTP-U interface
17S4 SGSN GTP-C interface
18S16 SGSN GTP-C interface
19eNodeB GTP-U interface for DL data forwarding
20eNodeB GTP-U interface for UL data forwarding
21RNC GTP-U interface for data forwarding
22SGSN GTP-U interface for data forwarding
23SGW GTP-U interface for DL data forwarding
24Sm MBMS GW GTP-C interface
25Sn MBMS GW GTP-C interface
26Sm MME GTP-C interface
27Sn SGSN GTP-C interface
28SGW GTP-U interface for UL data forwarding
29Sn SGSN GTP-U interface
30S2b ePDG GTP-C interface
31S2b-U ePDG GTP-U interface
32S2b PGW GTP-C interface
33S2b-U PGW GTP-U interface

I also found how this data is encoded on the wire is a bit strange,

In the example above the Interface Type is 7,

This is encoded in binary which give us 111.

This is then padded to 6 bits to give us 000111.

This is prefixed by two additional bits the first denotes if IPv4 address is present, the second bit is for if IPv6 address is present.

Bit 1Bit 2Bit 3-6
IPv4 Address Present IPv4 Address PresentInterface Type
11 000111

This is then encoded to hex to give us 87

Here’s my Python example;

interface_type = int(7)
interface_type = "{0:b}".format(interface_type).zfill(6)   #Produce binary bits
ipv4ipv6 = "10" #IPv4 only
interface_type = ipv4ipv6 + interface_type #concatenate the two
interface_type  = format(int(str(interface_type), 2),"x") #convert to hex

VoLTE Logo on Samsung Galaxy Handset

Things I wish I knew about setting up private VoLTE Networks

I’ve been working for some time on open source mobile network cores, and one feature that has been a real struggle for a lot of people (Myself included) is getting VoLTE / IMS working.

Here’s some of the issues I’ve faced, and the lessons I learned along the way,

Sadly on most UEs / handsets, there’s no “Make VoLTE work now” switch, you’ve got a satisfy a bunch of dependencies in the OS before the baseband will start sending SIP anywhere.

Get the right Hardware

Your eNB must support additional bearers (dedicated bearers I’ve managed to get away without in my testing) so the device can setup an APN for the IMS traffic.

Sadly at the moment this rules our Software Defined eNodeBs, like srsENB.

In the end I opted for a commercial eNB which has support for dedicated bearers.

ISIM – When you thought you understood USIMs – Guess again

According to the 3GPP IMS docs, an ISIM (IMS SIM) is not a requirement for IMS to work.

However in my testing I found Android didn’t have the option to enable VoLTE unless an ISIM was present the first time.

In a weird quirk I found once I’d inserted an ISIM and connected to the VoLTE network, I could put a USIM in the UE and also connect to the VoLTE network.

Obviously the parameters you can set on the USIM, such as Domain, IMPU, IMPI & AD, are kind of “guessed” but the AKAv1-MD5 algorithm does run.

Getting the APN Config Right

There’s a lot of things you’ll need to have correct on your UE before it’ll even start to think about sending SIP messaging.

I was using commercial UE (Samsung handsets) without engineering firmware so I had very limited info on what’s going on “under the hood”. There’s no “Make VoLTE do” tickbox, there’s VoLTE enable, but that won’t do anything by default.

In the end I found adding a new APN called ims with type ims and enabling VoLTE in the settings finally saw the UE setup an IMS dedicated bearer, and request the P-CSCF address in the Protocol Configuration Options.

Also keep in mind on Android at least, what you specify as your APN might be ignored if your UE thinks it knows best – Thanks to the Android Master APN Config – which guesses the best APN for you to use, which is a useful feature to almost any Android user, except the very small number who see fit to setup their own network.

Get the P-GW your P-CSCF Address

If your P-GW doesn’t know the IP of your P-CSCF, it’s not going to be able to respond to it in the Protocol Configuration Options (PCO) request sent by the UE with that nice new bearer for IMS we just setup.

There’s no way around Mutual Authentication

Coming from a voice background, and pretty much having RFC 3261 tattooed on my brain, when I finally got the SIP REGISTER request sent to the Proxy CSCF I knocked something up in Kamailio to send back a 200 OK, thinking that’d be the end of it.

For any other SIP endpoint this would have been fine, but IMS Clients, nope.

Reading the specs drove home the same lesson anyone attempting to setup their own LTE network quickly learns – Mutual authentication means both the network and the UE need to verify each other, while I (as the network) can say the UE is OK, the UE needs to check I’m on the level.

For anyone not familiar with the intricacies of 3GPP USIM Network Authentication, I’ve written about Mutual Network Authentication in this post.

In the end I added Multimedia Authentication support to PyHSS, and responded with a Crypto challenge using the AKAv1-MD5 auth,

For anyone curious about what goes on under the hood with this, I wrote about how the AKAv1-MD5 Authentication algorithm works in this post,

I saw my 401 response go back to the UE and then no response. Nada.

This led to my next lesson…

There’s no way around IPsec

According to the 3GPP docs, support for IPsec is optional, but I found this not to be the case on the handsets I’ve tested.

After sending back my 401 response the UE looks for the IPsec info in the 401 response, then tries to setup an IPsec SA and sends ESP packets back to the P-CSCF address.

Even with my valid AKAv1-MD5 auth, I found my UE wasn’t responding until I added IPsec support on the P-CSCF, hence why I couldn’t see the second REGISTER with the Authentication Info.

After setting up IPsec support, I finally saw the UE’s REGISTER with the AKAv1-MD5 authentication, and was able to send a 200 OK.

For some more info on ESP, IPsec SAs and how it works between the UE and the P-CSCF there’s a post on that too.

Get Good at Mind Reading (Or an Engineering Firmware)

To learn all these lessons took a long time,

One thing I worked out a bit late but would have been invaluable was cracking into the Engineering Debug options on the UEs I was testing with.

Samsung UEs feature a Sysdump utility that has an IMS Debugging tool, sadly it’s only their for carriers doing IMS interop testing.

After a bit of work I detailed in this post – Reverse Engineering Samsung Sysdump Utils to Unlock IMS Debug & TCPdump on Samsung Phones – I managed to create a One-Time-Password generator for this to generate valid Samsung OTP keys to unlock the IMS Debugging feature on these handsets.

I outlined turning on these features in this post.

This means without engineering firmware you’re able to pull a bunch of debugging info off the UE.

If you’ve recently gone through this, are going through this or thinking about it, I’d love to hear your experiences.

I’ll be continuing to share my adventures here and elsewhere to help others get their own VoLTE networks happening.

If you’re leaning about VoLTE & IMS networks, or building your own, I’d suggest checking out my other posts on the topic.

SIP SIMPLE – Instant Messaging with SIP

People think SIP they think VoIP & phone calls, but SIP it’s the Phone Call Initiation Protocol it’s the Session Initiation Protocol – Sure VoIP guys like me love SIP, but it’s not just about VoIP.

Have you sent an SMS on a modern mobile phone recently? Chances are you sent a SMS over SIP using SIP MESSAGE method.

So let’s look a bit at SIP SIMPLE, the catchily titled acronym translates to Session Initiation Protocol for Instant Messaging and Presence Leveraging Extensions (Admittedly less catchy in it’s full form).

There’s two way SIP SIMPLE can be used to implement Instant Messaging, Paging Mode with each message sent as a single transaction, and Session Mode where a session is setup between users and IMs exchanged with the same Call ID / transaction.

I’m going to cover the Paging Mode implementation because it’s simpler easier to understand.

Before we get too far this is another example of confusing terminology, let’s just clear this up; According to the RFC any SIP request is a SIP Message, like a SIP OPTIONS message, a SIP INVITE message. But the method of a SIP INVITE message is INVITE, the method of a SIP OPTIONS message is OPTIONS. There’s a SIP MESSAGE method, meaning you can send a SIP MESSAGE message using the MESSAGE method. Clear as mud? I’ll always refer to the SIP Method in Capitals, like MESSAGE, INVITE, UPDATE, etc.

The SIP MESSAGE Method

The basis of using SIP for instant messaging relies on the MESSAGE method, laid out in RFC 3428.

The SIP MESSAGE method looks / acts very similar to a SIP INVITE, in that it’s got all the standard SIP headers, but also a Message Body, in which our message body lives (funny about that), typically we’ll send messages using the Content-Type: text/plain to denote we’re sending a plaintext message.

Example MESSAGE Message Flow

Like a SIP OPTIONS Method, the MESSAGE method is simply answered with a 200 OK (No Ack).

Let’s have a look at how the MESSAGE message looks:

MESSAGE sip:[email protected] SIP/2.0
Via: SIP/2.0/TCP user1pc.domain.com;branch=z9hG4bK776sgdkse
Max-Forwards: 70
From: sip:[email protected];tag=49583
To: sip:[email protected]
Call-ID: [email protected]
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 18

Hello world.

After receiving the SIP MESSAGE message, the recipient simply sends back a 200 OK with the same Call-ID.

Simple as that.

You can read more about the SIP MESSAGE method in RFC 3428.

I used the SIP MESSAGE method in a Kamailio Bytes example recently where I sent a MESSAGE to an IP phone when a HTTP GET was run against Kamailio, and again to send an alert when an emergency services destination was called.

PyHSS Update – IMS Cx Support!

As I’ve been doing more and more work with IMS / VoLTE, the requirements / features on PyHSS has grown.

Some key features I’ve added recently:

IMS HSS Features

IMS Cx Server Assignment Request / Answer

IMS Cx Multimedia Authentication Request / Answer

IMS Cx User Authentication Request / Answer

IMS Cx Location Information Request / Answer

General HSS Features

Better logging (IPs instead of Diameter hostnames)

Better Resync Support (For USIMs with different sync windows)

ToDo

There’s still some functions in the 3GPP Cx interface description I need to implement:

IMS Cx Registration-Termination Request / Answer

IMS Cx Push-Profile-Request / Answer

Support for Resync in IMS Cx Multimedia Authentication Answer

Keep an eye on the GitLab repo where I’m pushing the changes.

If you’re leaning about VoLTE & IMS networks, or building your own, I’d suggest checking out my other posts on the topic.

IMS / VoLTE IPsec on the Gm Interface

For most Voice / Telco engineers IPsec is a VPN technology, maybe something used when backhauling over an untrusted link, etc, but voice over IP traffic is typically secured with TLS and SRTP.

IMS / Voice over LTE handles things a bit differently, it encapsulates the SIP & RTP traffic between the UE and the P-CSCF in IPsec Encapsulating Security Payload (ESP) payloads.

In this post we’ll take a look at how it works and what it looks like.

It’s worth noting that Kamailio recently added support for IPsec encapsulation on a P-CSCF, in the IMS IPSec-Register module. I’ll cover usage of this at a later date.

The Message Exchange

The exchange starts off looking like any other SIP Registration session, in this case using TCP for transport. The UE sends a REGISTER to the Proxy-CSCF which eventually forwards the request through to a Serving-CSCF.

This is where we diverge from the standard SIP REGISTER message exchange. The Serving-CSCF generates a 401 Unauthorized response, containing an authentication challenge in the WWW-Authenticate header, and also a Ciphering Key & Integrity Key (ck= and ik=) also in the WWW-Authenticate header.

The Serving-CSCF sends the Proxy-CSCF the 401 response it created. The Proxy-CSCF assigns a SPI for the IPsec ESP to use, a server port and client port and indicates the used encryption algorithm (ealg) and algorithm to use (In this case HMAC-SHA-1-96.) and adds a new header to the 401 Unauthorized called SecurityServer header to share this information with the UE.

The Proxy-CSCF also strips the Ciphering Key (ck=) and Integrity Key (ik=) headers from the SIP authentication challenge (WWW-Auth) and uses them as the ciphering and integrity keys for the IPsec connection.

Finally after setting up the IPsec server side of things, it forwards the 401 Unauthorized response onto the UE.

Upon receipt of the 401 response, the UE looks at the authentication challenge.

Keep in mind that the 3GPP specs dictate that IMS / VoLTE authentication requires mutual network authentication meaning the UE authenticates the network as well as the network authenticating the UE. I’ve written a bit about mutual network authentication in this post for anyone not familiar with it.

If the network is considered authenticated by the UE it generates a response to the Authentication Challenge, but it doesn’t deliver it over TCP. Using the information generated in the authentication challenge the UE encapsulates everything from the network layer (IPv4) up and sends it to the P-CSCF in an IPsec ESP.

Communication between the UE and the P-CSCF is now encapsulated in IPsec.

Wireshark trace of IPsec IMS Traffic between UE and P-CSCF

If you’re leaning about VoLTE & IMS networks, or building your own, I’d suggest checking out my other posts on the topic.

SIP Supported & Require

On top of plain vanilla RFC3261, there’s a series of “Extension” methods added to SIP to expand it’s functionality, common extension methods are INFO, MESSAGE, NOTIFY, PRACK and UPDATE. Although now commonplace, of these is not defined in RFC3261 so is considered an “extension” to SIP.

It’s worth just pausing here to reiterate we’re not talking extensions like in a PBX context, like extra phones, we’re talking extensions like you’d add to a house, like extra functionality.

A SIP client can request functionality from a server (UAC to a UAS), if the server does not have support for that functionality, it can reject the session on those grounds and send back a response indicating it doesn’t know how to handle that extension, like a 420 Bad ExtensionBad SIP Protocol Extension used, not understood by the server. Response.

So clients can determine what functionality a server doesn’t support if it rejects the request, but there was no way to see what functionality the server does support, and what functionality the client requires.

Enter the Supported header, initially drafted by Rosenberg & Schulzrinne in 2000, it made it into the SIP we know today (SIP v2 / RFC3261).

If a UAC or UAS requires support for an extension – For example a Media Gateway has to understand PRACK, it can use the Require header to specify the request should be rejected if support for the listed extensions is not provided.

These headers are most commonly seen in SIP OPTIONS requests.

PLMN Identity from Wireshark in Hex Form

PLMN Identifier Calculation (MCC & MNC to PLMN)

Note: This didn’t handle 3 digit MNCs, an updated version is available here and in the code sample below.

The PLMN Identifier is used to identify the radio networks in use, it’s made up of the MCC – Mobile Country Code and MNC – Mobile Network Code.

But sadly it’s not as simple as just concatenating MCC and MNC like in the IMSI, there’s a bit more to it.

In the example above the Tracking Area Identity includes the PLMN Identity, and Wireshark has been kind enough to split it out into MCC and MNC, but how does it get that from the value 12f410?

This one took me longer to work out than I’d like to admit, and saw me looking through the GSM spec, but here goes:

PLMN Contents: Mobile Country Code (MCC) followed by the Mobile Network Code (MNC).
Coding: according to TS GSM 04.08 [14].

If storage for fewer than the maximum possible number n is required, the excess bytes shall be set to ‘FF’. For instance, using 246 for the MCC and 81 for the MNC and if this is the first and only PLMN, the contents reads as follows: Bytes 1-3: ’42’ ‘F6′ ’18’ Bytes 4-6: ‘FF’ ‘FF’ ‘FF’ etc.

TS GSM 04.08 [14].

Making sense to you now? Me neither.

Here’s the Python code I wrote to encode MCC and MNCs to PLMN Identifiers and to decode PLMN into MCC and MNC, and then we’ll talk about what’s happening:

def Reverse(str):
    stringlength=len(str)
    slicedString=str[stringlength::-1]
    return (slicedString)    

def DecodePLMN(plmn):
    print("Decoding PLMN: " + str(plmn))
    
    if "f" in plmn:
        mcc = Reverse(plmn[0:2]) + Reverse(plmn[2:4]).replace('f', '')
        print("Decoded MCC: " + str(mcc))
        mnc = Reverse(plmn[4:6])
    else:
        mcc = Reverse(plmn[0:2]) + Reverse(plmn[2:4][1])
        print("Decoded MCC: " + str(mcc))
        mnc = Reverse(plmn[4:6]) + str(Reverse(plmn[2:4][0]))
    print("Decoded MNC: " + str(mnc))
    return mcc, mnc

def EncodePLMN(mcc, mnc):
        plmn = list('XXXXXX')
        if len(mnc) == 2:
            plmn[0] = Reverse(mcc)[1]
            plmn[1] = Reverse(mcc)[2]
            plmn[2] = "f"
            plmn[3] = Reverse(mcc)[0]
            plmn[4] = Reverse(mnc)[0]
            plmn[5] = Reverse(mnc)[1]
            plmn_list = plmn
            plmn = ''
        else:
            plmn[0] = Reverse(mcc)[1]
            plmn[1] = Reverse(mcc)[2]
            plmn[2] = Reverse(mnc)[0]
            plmn[3] = Reverse(mcc)[0]
            plmn[4] = Reverse(mnc)[1]
            plmn[5] = Reverse(mnc)[2]
            plmn_list = plmn
            plmn = ''
        for bits in plmn_list:
            plmn = plmn + bits
        print("Encoded PLMN: " + str(plmn))
        return plmn

EncodePLMN('505', '93')
EncodePLMN('310', '410')

DecodePLMN("05f539")
DecodePLMN("130014")

In the above example I take MCC 505 (Australia) and MCC 93 and generate the PLMN ID 05f539.

The first step in decoding is to take the first two bits (in our case 05 and reverse them – 50, then we take the third and fourth bits (f5) and reverse them too, and strip the letter f, now we have just 5. We join that with what we had earlier and there’s our MCC – 505.

Next we get our MNC, for this we take bytes 5 & 6 (39) and reverse them, and there’s our MNC – 93.

Together we’ve got MCC 505 and MNC 93.

The one answer I’m still looking for; why not just encode 50593? What is gained by encoding it as 05f539?

PyHSS Update – MongoDB Backend & SQN Resync

After a few quiet months I’m excited to say I’ve pushed through some improvements recently to PyHSS and it’s growing into a more usable HSS platform.

MongoDB Backend

This has a few obvious advantages – More salable, etc, but also opens up the ability to customize more of the subscriber parameters, like GBR bearers, etc, that simple flat text files just wouldn’t support, as well as the obvious issues with threading and writing to and from text files at scale.

Knock knock.

Race condition.

Who’s there?

— Threading Joke.

For now I’m using the Open5GS MongoDB schema, so the Open5Gs web UI can be used for administering the system and adding subscribers.

The CSV / text file backend is still there and still works, the MongoDB backend is only used if you enable it in the YAML file.

The documentation for setting this up is in the readme.

SQN Resync

If you’re working across multiple different HSS’ or perhaps messing with some crypto stuff on your USIM, there’s a chance you’ll get the SQN (The Sequence Number) on the USIM out of sync with what’s on the HSS.

This manifests itself as an Update Location Request being sent from the UE in response to an Authentication Information Answer and coming back with a Re-Syncronization-Info AVP in the Authentication Info AVP. I’ll talk more about how this works in another post, but in short PyHSS now looks at this value and uses it combined with the original RAND value sent in the Authentication Information Answer, to find the correct SQN value and update whichever database backend you’re using accordingly, and then send another Authentication Information Answer with authentication vectors with the correct SQN.

SQN Resync is something that’s really cryptographically difficult to implement / confusing, hence this taking so long.

What’s next? – IMS / Multimedia Auth

The next feature that’s coming soon is the Multimedia Authentication Request / Answer to allow CSCFs to query for IMS Registration and manage the Cx and Dx interfaces.

Code for this is already in place but failing some tests, not sure if that’s to do with the MAA response or something on my CSCFs,

Keep an eye on the GitLab repo!

Authentication Vectors and Key Distribution in LTE

Querying Auth Credentials from USIM/SIM cards

LTE has great concepts like NAS that abstract the actual transport layers, so the NAS packet is generated by the UE and then read by the MME.

One thing that’s a real headache about private LTE is the authentication side of things. You’ll probably bash your head against a SIM programmer for some time.

As your probably know when connecting to a network, the UE shares it’s IMSI / TIMSI with the network, and the MME requests authentication information from the HSS using the Authentication Information Request over Diameter.

The HSS then returns a random value (RAND), expected result (XRES), authentication token (AUTN) and a KASME  for generating further keys,

The RAND and AUTN values are sent to the UE, the USIM in the UE calculates the RES (result) and sends it back to the MME. If the RES value received by the MME is equal to the expected RES (XRES) then the subscriber is mutually authenticated.

The osmocom guys have created a cool little utility called osmo-sim-auth, which allows you to simulate the UE’s baseband module’s calls to the USIM to authenticate.

Using this tool I was able to plug a USIM into my USIM reader, using the Diameter client built into PyHSS I was able to ask for Authentication vectors for a UE using the Authentication Information Request to the HSS and was sent back the Authentication Information Answer containing the RAND and AUTN values, as well as the XRES value.

Wireshark Diameter Authentication Information Response message body looking at the E-UTRAN vectors
Diameter – Authentication Information Response showing E-UTRAN Vectors

Then I used the osmo-sim-auth app to query the RES and RAND values against the USIM.

Osmocom's USIM Test tool - osmo-sim-auth

The RES I got back matched the XRES, meaning the HSS and the USIM are in sync (SQNs match) and they mutually authenticated.

Handy little tool!

Why GTP for Mobile Networks?

Let’s take a look at GTP, the workhorse of mobile user plane packet data.

This post covers all generations of mobile data (2.5 -> 5G), so I’m using generic terms.

GSM, UMTS, LTE & NR all have one protocol in common – GTP – The GPRS Tunneling Protocol.

So why do every generation of mobile data networks from GSM/GPRS in 2000, to 5G NR Standalone in 2020, rely on this one protocol for transporting user data?

So Why GTP?

GTP – the GPRS Tunnelling Protocol, is what encapsulates and tunnels IP packets from the internet / packet data network, to and from the User.

So why encapsulate the packets? What if the Base Station had access to the internet and routed the traffic to the users?

Let’s say we did that, we’d have to have large pools of IP addresses available at each Base Station and when a user connected they’d be assigned an IP Address and traffic for these users would be routed to the Base Station which would forward it onto the user.

This would work well until a user moves from one Base Station to another, when they’d have to get a new IP Address allocated.

TCP/IP was never designed to be mobile, an IP address only exists in a single location.

Breaking out traffic directly from a base station would have other issues, such as no easy way to enforce QoS or traffic policies, meter usage, etc.

How to fix IP’s lack of mobility? GTP.

GTP addressed the mobility issue by having a single fixed point the IP Address is assigned to (In GSM/GRPS/UMTS this is the Gateway GPRS Support Node, in LTE this is the P-GW and in 5G-SA this is the UPF), which encapsulates IP traffic to/from a mobile user into GTP Packet.

You can think of GTP like GRE or any of the other common encapsulation protocols, wrapping up the IP packets into a GTP packet which we can rerouted to different Base Stations as the users move from being served by one Base Station to another.

This easy redirecting / rerouting of user traffic is why GTP is used for NR (5G), LTE (4G), UMTS (3G) & GPRS (2.5G) architectures.

GTP Packets

When looking at a GTP packet of user data you’d be forgiven for thinking nothing much goes on,

Example GTP packet containing a DNS query

Like in most tunneling / encapsulation protocols we’ve got the original network / protocol stack of IPv4 and UDP, and a payload of a GTP packet.

The packet itself is pretty bare bones, there’s flags, denoting a few basics like version number, the message type (T-PDU), the length of the GTP packet and it’s payload (used for delineating the end of the payload), a sequence number an a Tunnel Endpoint Identifier (TEID).

In the payload, we can see the network / protocol stack and application layer of the contents of the GTP packet.

From a mobility standpoint, the beauty of GTP is that it takes IP packets and puts them into a media stream of sorts, with out of band signalling, this means we can change the parameters of our GTP stream easily without touching the encapsulated IP Packet.

When a UE moves from one base station to another, all that has to happen is the destination the GTP packets are sent to is changed from the old base station to the new base station. This is signalled using GTP-C in GPRS/UMTS, GTPv2-C in LTE and HTTP in 5G-SA.

Traffic to and from the UE would look the same as the screenshot above, the only difference would be the first IPv4 address would be different, but the IPv4 address in the GTP tunnel would be the same.

LNP / Porting FAQ

This is a follow up to my other post on LNP (Anatomy of Local Number Porting in Australia) with some of the frequently asked questions.

For more info on the routing I’ve also written about Call Routing in LNP.

I’ve cited the relevant section of the code below and you can find the code itself here – Communications Alliance – Local Number Portability.

Why am I still billed after a number is ported out?

The Losing CSP does not need to take any action to disconnect Customer’s Telephone Number(s).

3.4.3

This means just porting out a number from a CSP doesn’t mean billing from the Loosing CSP will stop.

Continuing contractual agreements between the customer and Loosing CSP may still be in place and the customer is responsible for requesting the services be cancelled with the Loosing CSP.

Some CSPs work out that if you’re porting out a number you don’t want their services anymore, but they’re not obliged to and most will do what they can get away with.

What is a Bilateral Peering Agreement?

While a customer is legally entitled to move a number they have full control over (As outlined in Telecommunications Numbering Plan 2015), in practice phone numbers can only be moved from one carrier to another if both CSPs have a Bilateral Peering Agreement with each other.

These agreements primarily sort out the commercials of how much they’ll pay each other per port in / out.

It’s worth also noting that the Code only defines the minimum standard and process, two CSPs that have a bilateral peering agreement in place are able to process ports faster and more efficiently than the minimum standard outlined in the code.

Carriage Service Provider vs Carrier?

I’ve been sing the term Carriage Service Provider and Carrier interchangeably.

The difference as far as the code is concerned is one is who a customer pays for the service, while the other is the provider of the service. Generally it’s safe to assume that the CSP is also the Carrier and not a re-seller.

Donor Carriers

Under the Numbering Plan managed by ACMA numbers are allocated to certain CSPs.

These numbers can be ported to other CSPs (this is after all what LNP is all about) but after the number is routed to a different carrier the Donor Carrier remains the carrier listed in the Numbering Plan.

The Donor Carrier is responsible for Donor Transit Routing (A temporary redirect to numbers that have been ported away recently) for any numbers that have recently been ported out, and publishing the number and new carrier details for each number ported out in their PLNR file.

Donor Transit Routing

Under the Numbering Plan managed by ACMA numbers are allocated to certain CSPs.

These numbers can be ported to other CSPs (this is after all what LNP is all about) but after the number is routed to a different carrier the Donor Carrier remains the carrier listed in the Numbering Plan.

In a scenario where a call needs to route to a destination where the current carrier for that destination is unknown, the call is routed to the Donor Carrier, as that’s who the number is originally allocated to by ACMA.

Upon reciept of a call by the donor carrier to a number that has been ported out, the donor’s switch finds the correct Access Service Deliver (ASD) and redirects the call to them.

This is a temporary service – CSPs are only obliged to do this for 5 days, after which it’s assumed the PLNR file of the donor will have been read by all the other CSPs and they’ll be routing the traffic to the correct CSP and not the Donor CSP.

Third Party Ports

Third Party Porting is where the Donor Carrier is neither the Losing Carrier or the Gaining Carrier. Third Party Porting requires bilateral agreements to be in place between each of the parties involved.

As we just covered ACMA allocates numbers to CSPs, when a number is ported to a different CSP the number is still allocated to the original CSP as far as ACMA and The Numbering System are concerned.

The CSP the number was originally allocated to is the Donor CSP – forever.

Let’s look at a two party port first:

  • A number is allocated by ACMA to CSP 1
  • The customer using that number decides to port the to CSP 2 using the standard LNP process
  • CSP 1 performs Donor Transit Routing for the required 5 days and updates it’s PLNR file to denote that the number has been ported to CSP 2

Now let’s consider a three party port, carrying on from the steps above.

  • The Customer decides they want to move from CSP 2 to another CSP – CSP 3
  • At the time of the port the donor CSP (CSP 1) must:
  • CSP 1 must update it’s PLNR records for this number to denote it’s no longer with CSP 2 but is now with CSP 3
  • CSP 1 must provide Donor Transit Routing for the required 5 business days – redirecting calls to CSP 3

So even though the number is moving from CSP 2 to CSP 3 as the number was originally allocated to CSP 1, it is, and will always be the Donor Carrier and as such has to provide Donor Transit Routing and update it’s PLNR each time the number is ported.

Port Reversal / Emergency Return

Ports have an emergency return window inside which the port can be reverted. For Cat C ports this invovles the project manager of one CSP contacting the project manager for the other CSP and requesting the return.

In the event the end customer has requested the Port Reversal / Emergency return they’re typically liable for a very hefty fee to do so.

Give Back & Quarantine of Numbers

After a number is no longer required, it’s given back to the donor carrier who places it in quarantine and typically does not reallocate the number for 6 months.

In some cases such as a wronly cancelled number the customer may be able to get a number that’s been cancelled back while it’s in it’s quarantine state, however this is not required and up to the donor carrier.

Including Customer Account Numbers when Porting

Prior to 2016, a customer moving from one CSP to another CSP were required to include their account number (“Service Account Number”) they had with the Loosing CSP to the Gaining CSP when submitting the Port which was verified against the Loosing Carrier’s records to ensure the correct Customer / Service combo.

This led to a lot of ports being rejected unnecessarily due to mismatched account numbers, as such the the requirement to include a valid matching account number with the loosing CSP has been removed.

Service Account is to remain as a mandatory field, and a standard validation but any mismatches are not to be rejected.

Where’s Cat B & Cat D?

Cat B Dropped in 2013 revision due to lack of use.

Cat D is almost the same as a Cat A port but allows services with an active ULL diversion to be ported. These are quite rare and a very specific use case.

Why is my Cat C Port taking so long?

You may find after submitting a port the date you’ve got back for porting is months away. The Loosing Carrier sets the porting date, and as they’re loosing the customer, they’re often not so keen to action the port quickly when they’re loosing the customer after all.

Lead Times are determined by the Losing Carrier. These may vary by product including variations due to the size of the product or the number of sites to which a particular service is offered.

3.5.10

Tidbit: One of Australia’s largest carriers has a 20,000 number per day limit on porting, meaning they’re only able to process up to 20,000 ports per day in or out. Once that limit is reached no more ports can be accepted for that day, so the ports are delayed until the next day, etc, etc, leading to considerable lead times.

The code requires CSPs to keep Service Metrics on porting time-frames, but there’s no penalty for being slow. (Section 3.6)

Third Party ports also take a lot longer due to the requirement to find a time window that suits all 3 carriers.

Can I arrange my numbers to be Ported after-hours?

CSPs are not required to port numbers outside of the “Standard Hours” defined in the code. (Section 3.8.1 )

However, most CSPs have included support for this inside their bilateral agreements with other carriers. This typically costs more for the customer, but also comes with the added risk of if the port fails there are fewer technical / engineering resources available at the Loosing and Gaining Carrier’s respective ends to sort it out if something goes wrong.

What’s a PNO?

Porting Notification Order – A message containing either a Simple Notification Advise (SNO) for Simple (Cat A) ports, or a Complex Notification Advise (CNA) for Complex (Cat C) ports.

Each PNO contains a unique sequential reference number to differentiate / associate the PNO with a particular porting request.

PLNR – Ported Local Number Registry

PLNR is nothing more than a giant text file, containing a list of numbers originally allocated to that CSP but that have been ported to another CSP, and with each number that’s been ported out the carrier code of the CSP it’s now with.

Information to facilitate Call Routing is provided by the Donor Carrier who is required to notify Carriers, via a Ported Local Number Register, that a Port is pending, completed or did not proceed. This relates to all Ports, including Third Party Ports. All participants must use the Ported Local Number Registers to determine the correct Call Routing.

Typically transferred via Web interface:

… a web site that contains a file with a list of Telephone Numbers that have been Ported away from the Donor, or have just returned.

PLNR data is encoded as a fixed-format text file.

What is Re-targeting?

Re-Targeting is a fancy term of changing the date & time.

It’s typically more efficient to re-target a port than withdraw it and resubmit it.

For only two re-targets are allowed for each unique SNA. (Section 4.2.9)

Anatomy of Local Number Portability in Australia

The Australian telecommunications industry was deregulated in 1997, meaning customers could have telecommunications services through a Carriage Service Provider (CSP) of their choice.

In order to increase competition and make it easier to move to a different CSP, the ACMA (Or as they were then the ACA) declared that Local Numbers (Geo numbers / land lines) were a “Portable Service”. This meant that if a customer didn’t like their current Carriage Service Provider (CSP) they could give them the flick (making them the Loosing Carrier), move to a new CSP (Gaining Carrier) but keep their existing phone numbers by moving them to the new carrier in a process known as Local Number Portability (LNP).

The Local Number Portability (LNP) standard was first defined by Comms Alliance in 1999 in ACIF C540 and defines the process of moving numbers between Carriage Service Providers (CSPs), however 22 years later the process can still be a baffling system for many customers, end users and carrier staff to navigate.

Acronyms galore exist and often the porting teams involved themselves aren’t 100% sure what goes on in the porting process.

In 1997 ISDN was first still an emerging technology and porting was typically a customer moving from one PSTN / POTS line provided by one CSP to another PSTN / POTS line provided by a different CSP – a simple port.

Two processes were defined, one for managing simple ports involving moving one simple number from one CSP to another CSP – Called Simple Porting or “Cat A” – which made up the majority of porting requests at the time, and another process for everything else managed by a project manager from the Loosing and Gaining CSP called Complex Porting or “Cat C“.

Since 1997, the advent of the NBN, VoIP, SIP and the announcement that one of Australia’s largest carriers is shutting down their ISDN network by 2020, means that today the majority of ports a business customer will face will be Cat C – Complex Ports.

LNP is an issue worldwide, and ENUM was released to try and make this a bit better, however it had one short trial in Australia a long time ago and hasn’t been looked at since.

Cat A / Simple Number Porting

Simple porting, classified as “Cat A” is used for porting single simple services (numbers).

The Cat A process can only be used for moving a “simple” standalone number – with no additional features – from one carrier to another.

The typical use case for Cat A port is moving a one copper PSTN / POTS line (Active line with no Fax Duet, Line Hunt, etc) from one carrier to another – as I said before, Cat A ports made up the majority of porting requests when the system was first introduced as the vast majority of services were copper POTS lines.

The process is automated at both ends, essentially the carriers send each other the numbers to be moved (more on that later) and their switches automatically process this and begin routing the number.

These ports are typically completed within a few days to a week and the customer gets a notification when the port is completed.

Cat C / Complex Number Porting

For all number porting that don’t meet the very specific requirements of Cat A aren’t met – and sometimes even if they are met, ports are processed as Cat C ports.

Cat C ports require a project manager at both the Gaining Carrier and the Loosing Carrier to agree on the details for the port and the move the numbers, each using their own internal process.

Lead times on Cat C ports are long – and getting longer, so from submitting a port to it’s completion can take 90+ days, and there is no confirmation required to the customer to let them know the services have been ported successfully.

Administrative Process of Ports (CatA & CatC)

Strap yourself in for a whirlwind of acronyms…

The Code does not constrain two or more individual industry participants agreeing to different arrangements

Section 1.3.6

Because of this it means this is the minimum standard, some CSPs have improved upon this between each other, however there’s a bit of a catch 22 in that CSPs have no incentive to make porting numbers out easier, as they’re typically loosing that customer, so the process is typically not improved upon in any meaningful way that makes the customer experience easier.

Without further ado, here’s what Cat A & Cat C ports look like under the hood…

Note: These all assume the Losing CSP is also the Donor CSP. More on that in the LNP FAQ and Call Routing posts.

Cat A – Simple Porting – Process

Summary

Cat A ports are automated – The process involves CSPs transferring formatted data between each other and the process that goes on for these ports.

The Loosing CSP must use the Cat A process if the service meets the requirements to be ported under a Cat A and the Gaining Carrier has submitted it as a Cat A port. This means a Cat A port can’t be rejected by the loosing carrier as not a valid Cat A port to be resubmitted as a Cat C port, if it does actually meet the requirements for Cat A porting. That said numbers that are valid in terms of Cat A can be submitted as a Cat C, this is often cheaper than submitting multiple Cat A porting requests when you have more than 5 or so services to be ported.

Here’s a brief summary of the process:

  • Customer requests port and details are validated
  • Simple Notification Advice (SNA) is sent to the Loosing CSP via a Porting Notification Order (PNO) – Essentially a form send to the loosing CSP of the intention to port the service
  • Loosing CSP sends back SNA Confirmation Advice to confirm the service can be ported
  • Electronic Cutover Advice (ECA) sent by gaining CSP to indicate gaining CSP wanting to initiate port
  • Loosing CSP provides Donor Routing by essentially redirecting calls to the Gaining CSP
  • ECA Confirmation Advice sent by loosing CSP to denote the service has been removed from the loosing CSP’s network & number is with gaining CSP as far as they are concerned
  • Losing CSP updates a big text file (PLNR) with a list of numbers allocated to it, to show the numbers have been ported to a different carrier and indicates which carrier

We’ll talk about the technical process of how the data is transferred, what PLNR is and how routing is managed, later on.

In depth process:

Step 1 – Customer Authority

The Gaining CSP must obtain Customer’s Authority (CA) to port number (Section 4.1.2) – Typically this takes the form of a number porting form filled in by the customer, containing a list of numbers to port, account numbers with loosing carrier and date.

If requested by the customer the Loosing CSP must explain any costs / termination payments / contractual obligations to the customer (Section 4.1.4), however the Loosing CSP cannot reject the port based upon an outstanding contract being in place.

Step 2 – Validation

Before anything technical happens, the Gaining CSP must validate the porting request is valid – this means verifying:

  • The requested numbers are able to be ported under the selected method (Cat A or Cat C)
  • Confirming the date of the Customer Authority is less than 90 days old
  • The requested numbers must be recorded

In practice these 3 steps are typically handled by a single form filled out by the customer in the first step. (Section 4.1.5)

If requested by the Loosing CSP this Customer Authority information has to be given to the Loosing CSP. This typically happens in cases of disputed ownership / management of a number.

Step 3 – The SNA PNO

Once the Gaining CSP is satisfied the port is valid, a Simple Notification Advice (SNA) is sent to the Loosing CSP via a Porting Notification Order (PNO) (Section 4.2.2).

The PNO is essentially a form that includes:

  • Area Code & Telephone Number of service to be ported
  • Service Account number with Loosing CSP
  • Porting Category set to Cat A
  • Date of Customer Authority

The Loosing CSP must then validate this info, by checking: (Section 4.2.4)

  • The requested number is a Simple service (Meets the requirements of Cat A)
  • Is with the Loosing CSP (Has not been ported to another carrier already)
  • Is not disconnected or pending disconnection at the time the SNA was submitted
  • The Customer Authority (CA) date is not more than 90 days old
  • Does not currently have a port request pending

After the Loosing CSP has gone through this they will send back a SNA Confirmation Advice if the port request (SNA PNO) is valid or a SNA Reject Advice along with the phone number and reason for rejection if the port request is deemed invalid.

The confirmation, if SNA Confirmation Advice is received, is deemed valid for 30 days, after which the process would have to start again and the SNA PNO would have to be regenerated.

Step 4 – Electronic Cutover Advice (ECA)

After the Loosing CSP sends back a SNA Confirmation Advice, the gaining carrier sends the Loosing Carrier an Electronic Cutover Advice (ECA) via the Final Cutover Notification Interface (Section 4.2.24 ).

When the Loosing CSP get the ECA it’s showtime. The Loosing CSP checks that there’s a valid SNA in place for the number to be ported and that it’s less than 2 days old (Section 4.2.27).

If the Loosing CSP is not satisfied they send back a ECA Reject Advice listing the reason for rejection within 15 minutes (Section 4.2.32).

If all looks good, the Loosing Carrier sends the Gaining CSP back a ECA Confirmation Advice within 15 minutes (Section 4.2.33).

Now is when the magic happens – the Loosing CSP “ports out” that number via their internal process, for this they provide temporary Donor Transit Routing – Essentially redirecting any calls that come into the ported number to the new carrier.

Finally the Loosing CSP sends a Electronic Completion Advice (ECA) to confirm they’ve processed the port out from their network (Section 4.2.34).

Within a day of the port completing, the Losing CSP updates the Ported Local Number Registry (PLNR) to show the service has been ported out and the identifier of the gaining carrier the number has been ported to. PLNR is nothing more than a giant text file containing a list of all the numbers originally allocated to the Loosing CSP and the carrier code they should now be routing to, this data is published so the other CSPs can read it.

Other CSPs read this PLNR data and update their routing tables, meaning the calls will route directly to the new Gaining CSP, and the Donor Routing can be removed on the Losing CSPs switch.

Cat C – Complex Porting – Process

Summary

Cat C ports are a manually project managed, and unlike Cat A are not automated.

This means that the Loosing and Gaining CSP must both allocate a “project manager”, the two to liaise with each other (typically via email) to confirm the numbers can be ported and then find a suitable time to port the numbers, finally at the agreed upon date & time each side kicks off their own process to move the numbers and confirm when it’s done.

Porting Number Validation – PNV

Before a Cat C port can be initiated the PNV process is typically called upon to validate the port won’t get rejected. This isn’t mandatory but is often used as PNV is processed relatively quickly which means any issues with the services can be worked out prior to submitting the port request.

The submitted PNV request is very similar to the actual Cat C porting request (CNA), containing the customer’s details and list of services to be ported.

The loosing CSP returns the list of numbers each with a response code denoting particulars of the service, and if rejected, a rejection code.

Response Codes:

Reason CodeReason
P Prime/Directory Service Number
A Associated Service Numbers
SStandalone Number
RReserved Number
DExchange based diversion
SS Secondary Service linked to this Number (e.g. DSL)

Reject Codes:

CodeReason
1 Invalid Customer Authorization date Whole Request
2 Insufficient information supplied Whole Request
3 Telephone Number appears to belong to a completely different end customer Per Number
4 Telephone Numbers relate to cancelled services or services pending cancellation Per Number
5 Missing / invalid PNV Sequence Number Per Number
6 Telephone Numbers in the PNV request relate to services which are billed by a service provider other than the Losing Carrier. Per Number
7 Telephone Numbers are not found / not present on Losing Carrier’s Network Per Number

(Section 4.3.8)

It’s worth noting the main reason PNV is used so heavily in Cat C ports is if a batch of numbers / services are requested to be ported in a single Cat C porting request, if any one of those numbers gets rejected the whole port will need to be resubmitted, hence it being important that before submitting the numbers to be ported, the Gaining CSP verifies they can be ported via the PNV process.

The PNV does not guarantee a physical audit of the services, but rather an audit of available electronic data by the loosing CSP. It’s also only valid for the day of issue, so services can change between a PNV coming back clear and the port request being rejected.

99% of PNV requests should be processed within 5 business days. (Section 4.3.9)

Step 1 – Complex Notification Advice (CNA)

To initiate the port the gaining CSP submits a Complex Notification Advice (CNA) to the loosing CSP.

This contains all the data you’d expect, including customer’s details and the list of services/numbers to be ported, along with a batch number that’s unique to the Gaining CSP (Like a ticket / request number) and Gaining CSP’s Project Manager – The staff member as the Gaining CSP that will be responsible for the port.

Upon receipt, the Loosing CSP sends back a CNA Receipt Advice to confirm they’ve received and begins validating the CNA in a process very similar to the PNV process. (Section 4.4.1)

Step 2 – CNA Confirmation Advice

If verification fails and the CNA request is deemed not valid the CNA is rejected by the Loosing CSP, who sends back a CNA Reject Advice response. This response will contain a list of services and the reject code for each rejected service as per the PNV process.

If the CNA is deemed valid, the Loosing CSP responds with a CNA Confirmation Advice message, containing the Loosing CSP’s project manager for this port, along with the Gaining CSP’s batch number to the Gaining CSP.

This is sent in a batch file along with other CNA Confirmation Advice messages within 5 days. (Section 4.4.6)

Step 3 – Complex Cutover Advice (CCA)

Once the Gaining CSP has the CNA Confirmation Advice the project manager for the port at the Gaining CSP contacts the nominated project manager at the Loosing CSP and the two have to agree on a cutover date and time for the port. (Section 4.4.8)

The agreed date and time of the port is sent by the Gaining CSP to the Loosing CSP in the from of a Complex Cutover Advice (CCA) containing the Gaining CSP batch number and agreed date & time. (Section 4.4.27)

If the details of the CCA are valid from the Loosing CSP’s perspective, the Loosing CSP sends back CCA Confirmation Advice to confirm receipt.

Step 4 – The Porting

At the agreed upon date & time both CSPs are to execute the port from their organization’s perspective.

Typically the loosing CSP provides Donor Transit Routing forwarding / redirecting calls to the ported out number to the new CSP.

There is no completion advice and no verification the port has been completed successfully required by the code. (Section 4.4.48)

Within a day of the port completing, the Losing CSP updates the Ported Local Number Registry (PLNR).

Other CSPs read this PLNR data and update their routing tables, meaning the calls will route directly to the new Gaining CSP, and the Donor Routing can be removed on the Losing CSPs switch.

If you’ve made it this far I’m amazed. I’ve written two more posts on LNP that are relvant to this one, one with an FAQ on number porting, and another with info on how call routing in LNP works.

The case for Header Compression in VoIP/VoLTE

On a PCM (G.711) RTP packet the payload is typically 160 bytes per packet.

But the total size of the frame on the wire is typically ~214 bytes, to carry a 160 byte payload that means 25% of the data being carried is headers.

This is fine for VoIP services operating over fixed lines, but when we’re talking about VoLTE / IMS and the traffic is being transferred over Radio Access Networks with limited bandwidth / resources, it’s important to minimize this as much as possible.

IMS uses the AMR codec, where the RTP payload for each packet is around 90 bytes, meaning up to two thirds of the packet on the wire (Or in this case the air / Uu interface) is headers.

Enter Robust Header Compression which compresses the headers.

Using ROHC the size of the headers are cut down to only 4-5 bytes, this is because the IPv4 headers, UDP headers and RTP headers are typically the same in each packet – with only the RTP Sequence number, RTP timestamp IPv4 & UDP checksum and changing between frames.

SIP SDP – ptime

ptime is the packetization timer in VoIP, it’s set in the SDP message and defines the length of each RTP packet that’s sent;

This gives the length of time in milliseconds represented by the media in a packet. This is probably only meaningful for audio data, but may be used with other media types if it makes sense. It should not be necessary to know ptime to decode RTP or vat audio, and it is intended as a recommendation for the encoding/packetisation of audio. It is a media-level attribute, and it is not dependent on charset.

RFC 4556 – SDP: Session Description Protocol, Section 6
SDP body showing ptime value of 20ms

What it’s all about

A lower ptime value leads to more packet per second, while longer ptime leads to fewer packets per second.

In a Toll Quality (TDM) network 8000 samples per second are taken, this is reflected in PCM (Pulse Code Modulation) encoding of the data, see in PCMA / G.711 a-law for example.

But if each of these 8,000 samples per second were sent on an individual packet, we’d be seeing a huge number of tiny RTP packets where the header is a lot larger than the payload.

Instead endpoints generally wait until they’ve got a certain number of theses samples and then send them at once, every X milliseconds as defined by the ptime value.

  • A ptime of 1000ms would mean 1 packet per second.
  • A ptime of 20ms would mean 50 packets per second.
  • A ptime of 50ms would mean 20 packets per second.

ptime headaches

Some VoIP endpoints have issues with varied ptime (*cough Cisco SPA series cough*), and if you’re interconnecting with other carrier networks you have no real control as to what ptime endpoints use (except if you have a B2Bua that can resample / restuff the packets, or you use maxptime which really just limits more than fixes) so it’s worth understanding well.

International carrier trunks often have higher ptime values as they're often dealing with lower quality links, so they want to cut down the packets per second and often have jitter buffers in place to compensate for poor quality links.

RFC4566 (the second version of SDP) introduced the maxptime value.

This optional header in the SDP body allows an endpoint to specify the maximum ptime value it supports.

Older endpoints often don’t have much memory or processing power, so have very small buffers to store the received audio in before playing it to the user, and store the audio to be transmitted before sending it down the wire.

Mismatched ptime or a ptime that’s out of bounds for one endpoint can lead to some strange issues. Often an endpoint will ring, answer the call and even get a 200 OK, but immediately followed by a BYE from the incompatible end instead of an ACK.

In the initial INVITE ptime is not mandatory, meaning you may not know the caller has limits to the ptime values they can support, and the endpoint hangs up the calls straight after the 200 OK.

Identifying these issues may take some time, but here’s some good places to look:

  • SDP ptime value on INVITE and 200 OK
  • Time between RTP packets
  • Timestamp difference between RTP packets

Although it seems pretty self evident, if your endpoint only supports up to 20ms ptime, set the maxptime header to 20ms. You’d be surprised how often this isn’t the case.

You can read more about SDP on my Overview of SDP post and the RFC – RFC4566. You can lean about manipulating SDP headers in Kamailio in my post on SDPops.

SIP Extensions – Path

In vanilla RFC3261 SIP, a UA can only send a REGISTER request to a SIP Registrar.

It can’t go via any intermediary proxies.

That’s obviously a bit of a problem, as we build out our network we might have a series of load balancers that send traffic to a pool of Registrars, but according to RFC3261 this can’t be done, the SIP REGISTER request would need to go direct to one of these Registrars.

To get around this the SIP Path extensions, officially called “Session Initiation Protocol (SIP) Extension Header Field for Registering Non-Adjacent Contacts” (catchy title) was defined under RFC 3327.

An additional header is introduced called “Path:” for each proxy between the UA and the Registrar,

As the SIP REGISTER request passes through each proxy, each proxy appends the Path header with the value of it’s own SIP URI.

Let’s take a look at an example call flow from [email protected] who sends his REGISTER to atlanta.com, which is proxied by atlanta.com to registrar1.atlanta.com:

Bob to atlanta.com:

[email protected] > atlanta.com
      REGISTER sip:atlanta.com SIP/2.0
      Via: SIP/2.0/UDP 192.0.2.4:5060;branch=z9hG4bKnashds7
      To: Bob <sip:[email protected]>
      From: Bob <sip:[email protected]>;tag=456248
      Call-ID: 843817637684230@998sdasdh09
      CSeq: 1826 REGISTER
      Contact: <Bob <sip:[email protected]>>
      Supported: path

The REGISTER request is received by atlanta.com, which forwards it to registrar1.atlanta.com after adding it’s own URI as a Path header.

atlanta.com > registrar1.atlanta.com
      REGISTER sip:atlanta.com SIP/2.0
      Via: SIP/2.0/UDP atlanta.com;branch=z9hG4bK34ghi7ab04
      Via: SIP/2.0/UDP 192.0.2.4:5060;branch=z9hG4bKnashds7
      To: Bob <sip:[email protected]>
      From: Bob <sip:[email protected]>;tag=456248
      Call-ID: 843817637684230@998sdasdh09
      CSeq: 1826 REGISTER
      Contact: <Bob <sip:[email protected]>>
      Supported: path
      Path: <sip:atlanta.com;lr>

The response is sent back in the same way, relying on the via headers and Path headers.

The Sad story of ENUM in Australia

ENUM was going to change telephone routing. No longer would you need to pay a carrier to take your calls across the PSTN, but rather through the use of DNS your handset would look up a destination and route in a peer to peer fashion.

Number porting would just be a matter of updating NAPTR records, almost all calls would be free as there’s no way/need to charge and media would flow directly from the calling party to the called party.

In 2005 ACMA became the Tier 1 provider from RIPE for the ENUM zone 4.6.e164.arpa

A trial was run and Tier 2 providers were sought to administer the system and to verify ownership of services before adding NAPTR records for individual services and referral records for ranges / delegation.

In 2007 the trial ended with only two CSPs having signed up and a half a dozen test calls made between them.

Now, over a decade later as we prepare for the ISDN switch off, NBN is almost finished rolling out, the Comms Alliance porting specs remain as rigid as ever, it might be time to look again at ENUM in Australia…

PyHSS – Python 3GPP LTE Home Subscriber Server

I recently started working on an issue that I’d seen was to do with the HSS response to the MME on an Update Location Answer.

I took some Wireshark traces of a connection from the MME to the HSS, and compared that to a trace from a different HSS. (Amarisoft EPC/HSS)

The Update Location Answer sent by the Amarisoft HSS to the MME over the S6a (Diameter) interface includes an AVP for “Multiple APN Configuration” which has the the dedicated bearer for IMS, while the HSS in the software I was working on didn’t.

After a bit of bashing trying to modify the S6a responses, I decided I’d just implement my own Home Subscriber Server.

The Diameter interface is pretty straight forward to understand, using a similar structure to RADIUS, and with the exception of the Crypto for the EUTRAN Authentication Vectors, it was all pretty straight forward.

If you’d like to know more you can download PyHSS from my GitLab page, and view my Diameter Primer post and my post on Diameter packet structure.

NBNco Australia network map

Kamailio Bytes – Routing to geo local RTPengine Instances with Kamailio

I’m a big fan of RTPengine, and I’ve written a bit about it in the past.

Let’s say we’re building an Australia wide VoIP network. It’s a big country with a lot of nothing in the middle. We’ve got a POP in each of Australia’s capital cities, and two core softswitch clusters, one in Melbourne and one in Sydney.

These two cores will work fine, but a call from a customer in Perth, WA to another customer in Perth, WA would mean their RTP stream will need to go across your inter-caps to Sydney or Melbourne only to route back to Perth.

That’s 3,500Km each way, which is going to lead to higher latency, wasted bandwidth and decreased customer experience.

What if we could have an RTPengine instance in our Perth POP, handling RTP proxying for our Perth customers? Another in Brisbane, Canberra etc, all while keeping our complex expensive core signalling in just the two locations?

RTPengine to the rescue!

Preparing our RTPEngine Instances

In each of our POPs we’ll spin up a box with RTPengine,

We’d set it up in the way outlined in this post,

The only thing we’d do differently is set the listen-ng value to be 0.0.0.0:2223 and the interface to be the IP of the box.

By setting the listen-ng value to 0.0.0.0:2223 it’ll mean that RTPengine’s management port will be bound to any IP, so we can remotely manage it via it’s ng-control protocol, using the rtpengine Kamailio module.

Naturally you’d limit access to port 2223 only to allowed devices inside your network.

Adding Multiple RTP Engines to Kamailio Database

After adding database functionality to our Kamailio instance as we covered in this post, we’ll just need to add the follow lines to our config:

loadmodule "rtpengine.so"
modparam("rtpengine", "db_url", DBURL)
modparam("rtpengine", "table_name", "rtpengine")
modparam("rtpengine", "setid_avp", "$avp(setid)")

Next we’ll need to add the details of each of our RTP engine instances to MySQL, I’ve used a different setid for each of the RTPengines. I’ve chosen to use the first digit of the Zipcode for that state (WA’s Zipcodes / Postcodes are in the format 6xxx while NSW postcodes are look like 2xxx), we’ll use this later when we select which RTPengine instances to use.

I’ve also added localhost with setid of 0, we’ll use this as our fallback route if it’s not coming from Australia.

INSERT INTO `rtpengine` (`id`, `setid`, `url`, `weight`, `disabled`, `stamp`) VALUES (NULL, '6', 'udp:WA-POP.rtpengine.nickvsnetworking.com:2223', '1', '0', NOW());
INSERT INTO `rtpengine` (`id`, `setid`, `url`, `weight`, `disabled`, `stamp`) VALUES (NULL, '2', 'udp:NSW-POP.rtpengine.nickvsnetworking.com:2223', '1', '0', NOW());
INSERT INTO `rtpengine` (`id`, `setid`, `url`, `weight`, `disabled`, `stamp`) VALUES (NULL, '0', 'udp:localhost:2223', '1', '0', NOW());

We’ll restart Kamailio, and check the status of the RTPengines we added:

#> kamcmd rtpengine.show all
{
        url: udp:NSW-POP.rtpengine.nickvsnetworking.com:2223
        set: 2
        index: 1
        weight: 1
        disabled: 0
        recheck_ticks: 0
}
{
        url: udp:WA-POP.rtpengine.nickvsnetworking.com:2223
        set: 6
        index: 3
        weight: 1
        disabled: 0
        recheck_ticks: 0
}
{
        url: udp:localhost:2223
        set: 6
        index: 3
        weight: 1
        disabled: 0
        recheck_ticks: 0
}

Bingo, we’re connected to three RTPengine instances,

Next up we’ll use the Geoip2 module to determine the source of the traffic and route to the correct, I’ve touched upon the Geoip2 module’s basic usage in the past, so if you’re not already familiar with it, read up on it’s usage and we’ll build upon that.

We’ll load GeoIP2 and run some checks in the initial request_route{} block to select the correct RTPengine instance:

        if(geoip2_match("$si", "src")){
                if($gip2(src=>cc)=="AU"){
                        $var(zip) =  $gip2(src=>zip);
                        $avp(setid) = $(var(zip){s.substr,0,1});
                        xlog("rtpengine setID is $avp(setid)");
                }else{
                        xlog("GeoIP not in Australia - Using default RTPengine instance");
                        set_rtpengine_set("0");
                }
        }else{
                xlog("No GeoIP Match - Using default RTPengine instance");
                set_rtpengine_set("0");
        }

In the above example if we have a match on source, and the Country code is Australia, the first digit of the ZIP / Postcode is extracted and assigned to the AVP “setid” so RTPengine knows which set ID to use.

In practice an INVITE from an IP in WA returns setID 6, and uses our RTPengine in WA, while one from NSW returns 2 and uses one in NSW. In production we’d need to setup rules for all the other states / territories, and generally have more than one RTPengine instance in each location (we can have multiple instances with the same setid).

Hopefully you’re starting to get an idea of the fun and relatively painless things you can achieve with RTPengine and Kamailio!

SIP Extensions – History Info

The History Info extension defined in RFC7044 sets a way for an INVITE to include where the session (call) has been before that.

For example a call may be made to a desk phone, which is forwarded (302) to a home phone. The History Info extension would add a History Info header to the INVITE to the home phone, denoting the call had come to it via the desk phone.

Here the home phone can see the call first tried [email protected], at the same time tried [email protected] and [email protected] and [email protected], base don the index values.

More Info:

https://tools.ietf.org/html/rfc7044

https://tools.ietf.org/html/rfc7131

PyRTP – Simple RTP Library for Python

I recently had a scenario where I had to encode and decode RTP packets off the wire.

I wrote a Python Library to handle it which I’ve published for anyone to use.

Encoding data is quite simple, it takes a dictionary of values to fill the headers and payload and returns hex data to be sent down the wire:

payload = 'd5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5' 

packet_vars = {'version' : 2, 'padding' : 0, 'extension' : 0, 'csi_count' : 0, 'marker' : 0, 'payload_type' : 8, 'sequence_number' : 306, 'timestamp' : 306, 'ssrc' : 185755418, payload' : payload} 

PyRTP.GenerateRTPpacket(packet_vars)             #Generates hex to send down the wire 

And decoding is the same but reverse, feed it hex data and it returns a dict of values:

packet_bytes = '8008d4340000303c0b12671ad5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5'

rtp_params = PyRTP.DecodeRTPpacket(packet_bytes) #Returns dict of values from packet

Hopefully it’ll save someone else some time in the future.

For more info on RTP see:

RTP – More than you Wanted to Know for a deep dive into the packet structure