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).
TS GSM 04.08 [14].
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.
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.