Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

How and Why You Can Set Super SIM’s Network Attach Priority List


(warning)

Warning

The functionality described in this document applies only to card form-factor Super SIMs shipped after September 2021.

Every Super SIM, like all SIMs, includes a list of operator-preferred networks. This list, part of the 3GPP standard, is called the OPLMN (Operator-controlled Public Land Mobile Network) table and it sets the order in which the SIM's host cellular module contacts visible networks to request a network connection.

For example, Super SIM-empowered modems in the US first attempt to connect to AT&T because that's the first network (and only) listed in the OPLMN for the US. For Super SIM, the operator is, of course, Twilio. Other carriers are set as the Twilio-preferred network for other countries. The Super SIM OPLMN contains a single preferred network for each country.

Card form-factor Super SIMs issued after September 2021 allow you to override Twilio's OPLMN. This technique takes advantage of another 3GPP-standard SIM table: an optional list of user-preferred networks. This is the UPLMN (User-controlled Public Land Mobile Network) table. The cellular module must always select any network set in its SIM's UPLMN table, if it has one, over those in the OPLMN table. If it can't connect to the first user-preferred network, it tries the next one. If the UPLMN lacks an entry for any network visible to the modem, the SIM falls back on the OPLMN.

With just a few AT commands, your application can set its Super SIM's UPLMN table to list the networks you would like the SIM to use in preference to those specified by Twilio. This guide will show you how.

(information)

Info

The OPLMN is formally known as the 'OPLMNwAcT', and the UPLMN as the 'PLMNwAcT'. The 'wAcT' in each case is short for 'with Access Technology'. Here we'll stick with OPLMN and UPLMN, but you will see the other terms in 3GPP documentation. For full details of the encoding, please see ETSI Technical Specification 131 102(link takes you to an external page).


Why you might choose to set the preferred network

why-you-might-choose-to-set-the-preferred-network page anchor

First, let's consider why you might want to implement a UPLMN table. For the majority of customers, the network choices we have made are fine, but a small number of customers may discover during testing that an alternative network for the initial connection gives their particular choice of hardware better start-up performance. Or they are deploying in an area where Twilio's preferred network offers poorer coverage than another network. They can then set the UPLMN table in each of their Super SIMs so that their devices will favor that network.

For example, you might code your application to check the signal strength and backhaul bandwidth of each visible network at a device's location. The app might find that, say, the T-Mobile signal there is much stronger than the signal shown by OPLMN-prioritized AT&T. Or that though the AT&T signal is stronger, its backhaul is saturated so that the weaker signal T-Mobile tower delivers better throughput. In such cases, the application could write the UPLMN table to prioritize T-Mobile for that device.

Alternatively, you might want your devices in a given country to go straight to your NAP-selected network. By setting this network at the start of the UPLMN, you ensure the modem will go to it first and thus eliminate the time spent attempting to connect to other networks and in case failing because those networks are blocked by your NAP.

It's important to note, however, that better performance with a network not included in the OPLMN is often the result of where the test device is located, and may not be experienced by products that are rolled out more widely than the test area. Twilio's OPLMN choices are based on broad network coverage, not highly local coverage. Signal quality and network coverage may vary at any time, particularly when the device is moved or is in motion.

That said, your application may be location aware and therefore able to override the OPLMN with a UPLMN in certain cases where this is beneficial. Thorough testing and analysis will help you select the best network selection strategy to employ for your use case.


How does this differ from Network Access Profile network selection?

how-does-this-differ-from-network-access-profile-network-selection page anchor

You choose which networks to allow your devices to attach to, and which networks to block, using a given Fleet resource's Network Access Profile (NAP). Your network choices are enforced by the cell tower: networks blocked by your NAP will not allow the device to attach, even if that network is included in the UPLMN and/or OPLMN tables. The NAP cannot be used to create a list of networks to try in a particular order. The UPLMN is used solely to determine the order in which networks are contacted to request attachment. If there is no UPLMN, the modem will engage with the networks specified by the OPLMN. If a network is blocked by NAP, but is present in the UPLMN, the device will still try to attach to that network if it fails to connect to higher-priority networks. There is a small, but potentially significant latency in making such 'known to fail' attachment attempts, so you may wish to align your SIMs' UPLMNs to your NAP.

Here's the basic flow:

  1. The modem tries to connect to the network it was previously connected to. If this succeeds, it goes to 4.
  2. The modem iterates through the list of visible networks in the order set by the UPLMN and attempts to attach to each in turn. If it connects, it jumps to 4. If the network is blocked by the current NAP, the attachment attempt will fail, and the modem will move to the next network on the list. If there is no UPLMN, the modem will jump to 3.
  3. The modem iterates through the list of visible networks in the order set by the OPLMN and attempts to attach to each in turn. If the network is blocked by the current NAP, the attachment attempt will fail, and the modem will move to the next network on the list.
  4. The modem attaches to the network. It will reattach to this network after sleep. The modem remains attached to this network as long the signal strength allows it to do so. If there is a loss of signal, the modem returns to 1.

How to set a SIM's UPLMN table

how-to-set-a-sims-uplmn-table page anchor

To read and update a SIM's data files, including the OPLMN and UPLMN tables, you use the standard AT command +CRSM.

SIM commands are issued as data structures called Application Protocol Data Units (APDUs). We won't cover the full data structure here — for that, we recommend you check out ETSI Technical Specification 102 221(link takes you to an external page) — but essentially it contains an instruction-type byte, a number of instruction-specific parameter values, and the number of data bytes being read or written, if any.

+CRSM allows you to send the key elements of an APDU to the SIM in an easy way: as the AT command's parameters. To demonstrate this, let's use +CRSM to read a Super SIM's OPLMN.

Read the OPLMN

The OPLMN is stored in an 'Elementary File' (EF) on the SIM. The file is said to be 'transparent'. In other words, it consists of a sequence of bytes. Transparent files are read using the Read Binary SIM command.

(information)

Info

We'll assume you know how to issue AT commands to a cellular module. If you're not sure, this is how we did it for this guide. We connected a Sixfab 3G-4G/LTE Base Hat and Tellit ME910C1-WW module to a Raspberry 400 Linux computer, and used the minicom serial communications tool to talk to the module. See our Super SIM Getting Started Guide for more details.

Get the first network in the OPLMN with


_10
AT+CRSM=176,28513,0,0,5

What does this mean? Let's decode each of the command's parameters in turn:

  1. The APDU instruction. In this case it's 176 which is the Read Binary instruction.
  2. The ID of the file we want to access. Here it's 28513 which is the ID of the OPLMN. In standards documentation this is usually given in its hexadecimal value, 0x6F61 . Likewise, the formal name of the file containing the OPLMN is the EFOPLMNwAcT.
  3. The first of two APDU instruction-specific parameter values. For a Read Binary instruction, this is the upper byte of a two-byte offset value. We want the first network, so the offset is 0 .
  4. The second APDU parameter, which in this case is the low byte of the offset. Again, it's 0 .
  5. The number of bytes to be read or written. This can be zero, but here we want 5 bytes, enough for one record. OPLMN and UPLMN network records are five bytes long: three for the Mobile Country Code (MCC)/Mobile Network Code (MNU) combination that identifies the network, and two bytes for the Radio Access Technology (RAT) used.

Issuing the AT command above returns:


_10
+CRSM: 144,0,1300144080
_10
_10
OK

Again, let's decode each of the response's parts:

  1. This is the first of two standard APDU status codes. The value 144 ( 0x90 ) indicates success.
  2. The second of the two standard APDU status codes. This is 0 on success, but can indicate a specific cause if the first status code indicates an error.
  3. The data returned, if any were requested. We asked for five bytes, and this was returned as five hexadecimal values. The five bytes comprise a three-byte MCC and MNC combination that indicates the PLMN, and two RAT indicator bytes.

The PLMN is coded as follows. Numbering the hex octets 1 to 6, from left to right:

MCC = octet 2 * 100 + octet 1 * 10 + octet 4, so, 130 decodes to 310 (US) MNC = octet 6 * 100 + octet 5 * 10 + octet 3, so 014 decodes to 410 (AT&T)

(information)

Info

The standard encoding is based on three-digit MCCs and MNCs. For two-digit values, a placeholder third digit is added: the character F. For example, the MNC 81 is encoded as 81F.

You can use this short Python script to convert a PLMN coding to MCC and MNC values:


_10
# Get a PLMN coding
_10
plmn = input("Enter a PLMN coding: ")
_10
if len(plmn) != 6:
_10
print("ERROR -- PLMN must be 6 hex digits")
_10
else:
_10
# Rearrange octets and output
_10
mcc = (plmn[1] + plmn[0] + plmn[3]).replace("F", "")
_10
mnc = (plmn[5] + plmn[4] + plmn[2]).replace("F", "")
_10
print("MCC:", mcc)
_10
print("MNC:", mnc)

For a complete utility that makes use of this code, see Super SIM UPLMN Codec, below.

The two-byte RAT value is encoded this way. The first two digits are the hex value 40 (64), which indicates a preference for E-UTRAN (4G). The second two digits are the hex value 80 (128), which indicates GSM as a secondary radio technology preference. For full details of the encoding, please see ETSI Technical Specification 131 102(link takes you to an external page).

Set the UPLMN table

Like the OPLMN table, the UPLMN table is placed in an Elementary File: EFPLMNwAcT, with the ID 0x6F60 (28512). The file must be 40 bytes size minimum, i.e., eight network entries formatted as described above. If that's too many entries for your needs, fill up the remaining bytes with 0xFF. On a new Super SIM, the table already contains 40 such bytes, so you need only overwrite some of them the desired records. But bear in mind that subsequent attempts to update the UPLMN with a shorter list will need to clear any unwanted network records with FFFFFFFFFF.

(information)

Info

You can use this short Python script to convert entered MCC and MNC values into PLMN record hex octets:


_13
# Get MCC and MNC values
_13
mcc = input("Enter an MCC: ")
_13
mnc = input("Enter an MNC: ")
_13
_13
# Assemble string
_13
# NOTE Use 'F' for unused columns, ie. '81' -> '81F'
_13
if len(mnc) < 3: mnc += "FFF"[:3 - len(mnc)]
_13
if len(mcc) < 3: mcc += "FFF"[:3 - len(mcc)]
_13
plmn = mcc + mnc
_13
_13
# Rearrange octets and output
_13
plmn = plmn[1] + plmn[0] + plmn[5] + plmn[2] + plmn[4] + plmn[3]
_13
print("UPLMN Encoding:", plmn)

For a complete utility that makes use of this code, see Super SIM UPLMN Codec, below.

Let's set the UPLMN table to T-Mobile and AT&T. The data for AT&T we already have, from reading the OPLMN: 130014. T-Mobile USA's MNC is 260. Encoding its MCC/MNC combination as described above yields 130062. Using the same RAT as above, 4080, we get:


_10
13006240801300144080

which we write to the UPLMN with the APDU Update Binary instruction, 214. The File ID in decimal is 28512. We're writing at the start of the file so the two offset bytes are once more both zero, but this time we're writing ten bytes — the sequence above shows hexadecimal octets, not a decimal value — so the final parameter is 10:


_10
AT+CRSM=214,28512,0,0,10,"13006240801300144080"

If the data is written correctly, you'll see:


_10
+CRSM: 144,0
_10
_10
OK

in response.

Check the write by reading back all of the UPLMN:


_10
AT+CRSM=176,28512,0,0,10

The response is:


_10
+CRSM: 144,0,32F405408032F4514080
_10
_10
OK

(information)

Info

We've issued the above AT commands directly to the cellular module, just as your application might do on start-up after checking a flag to see whether it has already set the UPLMN table. Alternatively, depending on the module you're using, you may be able to issue the necessary AT commands by way of SMS messages. Not all modules support this feature, however, so please check your device's documentation first if this approach appeals to you.


An alternative AT command

an-alternative-at-command page anchor

There is a potentially easier method for setting the UPLMN table than the one outlined above, 'potentially' because it's not available on all cellular modules so you will need to check the documentation for your chosen modem to see if you'll be able to use it. This alternative approach uses the +CPOL AT command. It stands for "Preferred Operator List", and it allows you to update the UPLMN table directly. You pass a table index value, a format marker for the next parameter, a cellular operator identifier, and the RATs enabled for it. The format marker tells the module whether the following cellular identifier is a short or long string, or a numerical code.

You can read the current UPLMN with AT+CPOL?, but you'll receive an error if it does not yet exist — no entries have been written to it.

To get a (long) list of operator codes, issue AT+COPN.

Some modems — the u-blox SARA-R5 is one example — allow you to specify which table — UPLMN, OPLMN or the HPLMN (Home Public Land Mobile Network) — +CPOL will write to or read from. By default it will be the former, but you can set it to another, though attempting to write to the OPLMN or HPLMN tables will result in an error. The command to change the target table is +CPLS. Pass 0 for the UPLMN, 1 for the OPLMN or 2 for the HPLMN.

For example, the call AT+CPLS=1;+CPOL?;+CPLS=0 will set the OPLMN as the +CPOL target, read the table, and then set the target back to the UPLMN.

For more details on using +CPOL, please see your modem's documentation.


Working with older Super SIMs

working-with-older-super-sims page anchor

As noted earlier, only card form-factor Super SIMs which shipped after September 2021 include a UPLMN table to which you can add preferred networks. Earlier Super SIMs lack this table, and attempts to update it will fail so with the response:


_10
ERROR

However, attempts to read the UPLMN, i.e., issuing AT+CRSM=176,28512,0,0,0, will elicit a seemingly successful response:


_10
+CRSM: 106,130
_10
_10
OK

In fact 106 (0x6A) is an APDU failure code indicating a bad parameter. The second value, 130 (0x82), narrows this down to "file not found" — there is no UPLMN table, file EFPLMNwAcT, on this SIM.

Your application code can use this pair of values to check whether its cellular module contains an older Super SIM without a UPLMN table. Do not rely on a direct error response from the modem. ETSI Technical Specification 131 102 list the possible error codes you may encounter.

You can read the OPLMN table on any Super SIM with AT+CRSM=176,28513,0,0,0.


You can find a complete utility to help you encode MCC-MNC pairs into UPLMN table entries, and to decode entries into MCC, MNC and RAT values, in our public GitHub repo(link takes you to an external page). The utility is written in Python 3 without further dependencies so will run on any system with Python 3 installed.


Rate this page: