laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/18649 
)

Change subject: Add support for ADF_USIM/EF_EHPLMN
......................................................................

Add support for ADF_USIM/EF_EHPLMN

If the EF.EHPLMN exists, it contains the "Equivalent Home PLMN List".
The odd part of that list is that it is not just a list of additional
PLMN identities, but if the first digits of the IMSI are *not* listed
in EF.EHPLMN, then the MCC/MNC of the IMSI prefix is suddently no
longer considered the home network, but the subscriber is roaming.

See TS 23.122: "If the HPLMN code derived from the IMSI is not present
in the EHPLMN list, then it shall be treated as a Visited PLMN for PLMN
selection purposes."

Change-Id: I22d96ab4a424ec5bc1fb02f5e80165c646a748d3
---
M pySim-read.py
M pySim/cards.py
M pySim/commands.py
M pySim/utils.py
M pysim-testdata/sysmoISIM-SJA2.ok
5 files changed, 83 insertions(+), 4 deletions(-)

Approvals:
  laforge: Looks good to me, approved; Verified



diff --git a/pySim-read.py b/pySim-read.py
index 69cab4d..d6674a5 100755
--- a/pySim-read.py
+++ b/pySim-read.py
@@ -241,6 +241,13 @@
        # Check whether we have th AID of USIM, if so select it by its AID
        # EF.UST - File Id in ADF USIM : 6f38
        if '9000' == card.select_adf_by_aid():
+               # EF.EHPLMN
+               if card.file_exists(EF_USIM_ADF_map['EHPLMN']):
+                       (res, sw) = card.read_ehplmn()
+                       if sw == '9000':
+                               print("EHPLMN:\n%s" % (res))
+                       else:
+                               print("EHPLMN: Can't read, response code = %s" 
% (sw,))
                # EF.UST
                (res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
                if sw == '9000':
diff --git a/pySim/cards.py b/pySim/cards.py
index 808fde1..2d779b3 100644
--- a/pySim/cards.py
+++ b/pySim/cards.py
@@ -24,6 +24,7 @@
 #

 from pySim.ts_51_011 import EF, DF
+from pySim.ts_31_102 import EF_USIM_ADF_map
 from pySim.utils import *
 from smartcard.util import toBytes

@@ -41,6 +42,13 @@
                print("warning: erasing is not supported for specified card 
type!")
                return

+       def file_exists(self, fid):
+               res_arr = self._scc.try_select_file(fid)
+               for res in res_arr:
+                   if res[1] != '9000':
+                       return False
+               return True
+
        def verify_adm(self, key):
                '''
                Authenticate with ADM key
@@ -262,6 +270,25 @@
                len = self._scc.record_size(ef)
                self._scc.update_record(ef, rec_no, "ff" * len, 
force_len=False, verify=True)

+class UsimCard(Card):
+       def __init__(self, ssc):
+               super(UsimCard, self).__init__(ssc)
+
+       def read_ehplmn(self):
+               (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'])
+               if sw == '9000':
+                       return (format_xplmn(res), sw)
+               else:
+                       return (None, sw)
+
+       def update_ehplmn(self, mcc, mnc):
+               data = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'], 
length=None, offset=0)
+               size = len(data[0]) // 2
+               ehplmn = enc_plmn(mcc, mnc)
+               data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], 
ehplmn)
+               return sw
+
+

 class _MagicSimBase(Card):
        """
@@ -552,7 +579,7 @@
                        return None
                return None

-class SysmoUSIMgr1(Card):
+class SysmoUSIMgr1(UsimCard):
        """
        sysmocom sysmoUSIM-GR1
        """
@@ -653,7 +680,7 @@
                        data, sw = self._scc.update_record('6f42', 1, 
lpad(p['smsp'], 80))


-class SysmoUSIMSJS1(Card):
+class SysmoUSIMSJS1(UsimCard):
        """
        sysmocom sysmoUSIM-SJS1
        """
@@ -1037,7 +1064,7 @@
                return None


-class SysmoISIMSJA2(Card):
+class SysmoISIMSJA2(UsimCard):
        """
        sysmocom sysmoISIM-SJA2
        """
@@ -1144,16 +1171,22 @@
                        if p.get('opc'):
                                self._scc.update_binary('af20', p['opc'], 17)

-               # update EF-USIM_AUTH_KEY in ADF.USIM
                self._scc.select_file(['3f00'])
                aid = self.read_aid()
                if (aid):
+                       # update EF-USIM_AUTH_KEY in ADF.USIM
                        self._scc.select_adf(aid)
                        if p.get('ki'):
                                self._scc.update_binary('af20', p['ki'], 1)
                        if p.get('opc'):
                                self._scc.update_binary('af20', p['opc'], 17)

+                       # update EF.EHPLMN in ADF.USIM
+                        if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
+                               if p.get('mcc') and p.get('mnc'):
+                                       sw = self.update_ehplmn(p['mcc'], 
p['mnc'])
+                                       if sw != '9000':
+                                               print("Programming EHPLMN 
failed with code %s"%sw)
                return


diff --git a/pySim/commands.py b/pySim/commands.py
index 7288b19..c260a97 100644
--- a/pySim/commands.py
+++ b/pySim/commands.py
@@ -100,6 +100,17 @@
        def sel_ctrl(self, value):
                self._sel_ctrl = value

+       def try_select_file(self, dir_list):
+               rv = []
+               if type(dir_list) is not list:
+                       dir_list = [dir_list]
+               for i in dir_list:
+                       data, sw = self._tp.send_apdu(self.cla_byte + "a4" + 
self.sel_ctrl + "02" + i)
+                       rv.append((data, sw))
+                       if sw != '9000':
+                               return rv
+               return rv
+
        def select_file(self, dir_list):
                rv = []
                if type(dir_list) is not list:
diff --git a/pySim/utils.py b/pySim/utils.py
index ac82774..dc14d58 100644
--- a/pySim/utils.py
+++ b/pySim/utils.py
@@ -125,6 +125,9 @@
 def hexstr_to_fivebytearr(s):
        return [s[i:i+10] for i in range(0, len(s), 10) ]

+def hexstr_to_threebytearr(s):
+       return [s[i:i+6] for i in range(0, len(s), 6) ]
+
 # Accepts hex string representing three bytes
 def dec_mcc_from_plmn(plmn):
        ia = h2i(plmn)
@@ -213,6 +216,25 @@
        res['status'] = h2i(hexstr[34:36])
        return res

+def dec_xplmn(threehexbytes):
+       res = {'mcc': 0, 'mnc': 0, 'act': []}
+       plmn_chars = 6
+       plmn_str = threehexbytes[:plmn_chars]                           # first 
three bytes (six ascii hex chars)
+       res['mcc'] = dec_mcc_from_plmn(plmn_str)
+       res['mnc'] = dec_mnc_from_plmn(plmn_str)
+       return res
+
+def format_xplmn(hexstr):
+       s = ""
+       for rec_data in hexstr_to_threebytearr(hexstr):
+               rec_info = dec_xplmn(rec_data)
+               if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
+                       rec_str = "unused"
+               else:
+                       rec_str = "MCC: %03d MNC: %03d" % (rec_info['mcc'], 
rec_info['mnc'])
+               s += "\t%s # %s\n" % (rec_data, rec_str)
+       return s
+
 def derive_milenage_opc(ki_hex, op_hex):
        """
        Run the milenage algorithm to calculate OPC from Ki and OP
diff --git a/pysim-testdata/sysmoISIM-SJA2.ok b/pysim-testdata/sysmoISIM-SJA2.ok
index fd3f252..6054840 100644
--- a/pysim-testdata/sysmoISIM-SJA2.ok
+++ b/pysim-testdata/sysmoISIM-SJA2.ok
@@ -100,6 +100,12 @@
        Service 58 - Extension 8
        Service 59 - MMS User Connectivity Parameters

+EHPLMN:
+        00f110 # MCC: 001 MNC: 001
+        ffffff # unused
+        ffffff # unused
+        ffffff # unused
+
 USIM Service Table: beff9f9de73e0408400170730000002e00000000
        Service 2 - Fixed Dialling Numbers (FDN)
        Service 3 - Extension 2

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/18649
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I22d96ab4a424ec5bc1fb02f5e80165c646a748d3
Gerrit-Change-Number: 18649
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-CC: gui...@gmail.com <gui...@gmail.com>
Gerrit-MessageType: merged

Reply via email to