From 6ca2fa7a5d4842793217473cf6c04b2b7b344375 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Feb 2022 16:29:31 +0100 Subject: [PATCH] Split EF.UST handling from EF.IST and EF.SST The existing code had the following serious problems: * when trying to update EF.SST or EF.IST, it would write to EF.UST ! * shell commands were called ust_* even for the EST/IST files Let's introduce the proper separation between what is shared and what is file-specific. Change-Id: Ie55669ca37a4762fac9f71b1db528ca67056e8dd --- pySim/cards.py | 17 +++++++ pySim/ts_31_102.py | 108 +++++++++++++++++++++++++++++---------------- pySim/ts_31_103.py | 28 +++++++++++- 3 files changed, 114 insertions(+), 39 deletions(-) diff --git a/pySim/cards.py b/pySim/cards.py index c3766e96..1ed1634f 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -425,6 +425,15 @@ class UsimCard(SimCard): EF_USIM_ADF_map['UST'], content) return sw + def update_est(self, service, bit=1): + (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EST']) + if sw == '9000': + content = enc_st(res, service, bit) + (res, sw) = self._scc.update_binary( + EF_USIM_ADF_map['EST'], content) + return sw + + class IsimCard(SimCard): @@ -566,6 +575,14 @@ class IsimCard(SimCard): sw) return uiari_recs + def update_ist(self, service, bit=1): + (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IST']) + if sw == '9000': + content = enc_st(res, service, bit) + (res, sw) = self._scc.update_binary( + EF_ISIM_ADF_map['IST'], content) + return sw + class MagicSimBase(abc.ABC, SimCard): """ diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py index 9105418e..8e2d1c86 100644 --- a/pySim/ts_31_102.py +++ b/pySim/ts_31_102.py @@ -542,8 +542,6 @@ class EF_UServiceTable(TransparentEF): def __init__(self, fid, sfid, name, desc, size, table, **kwargs): super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs) self.table = table - # add those commands to the general commands of a TransparentEF - self.shell_commands += [self.AddlShellCommands()] @staticmethod def _bit_byte_offset_for_service(service: int) -> Tuple[int, int]: @@ -587,6 +585,47 @@ class EF_UServiceTable(TransparentEF): out[byte_offset] |= (bit) << bit_offset return out + def ust_service_check(self, cmd): + """Check consistency between services of this file and files present/activated""" + # obtain list of currently active services + (service_data, sw) = cmd.rs.read_binary_dec() + active_services = [] + for s in service_data.keys(): + if service_data[s]['activated']: + active_services.append(s) + # iterate over all the service-constraints we know of + files_by_service = self.parent.files_by_service + try: + for s in sorted(files_by_service.keys()): + active_str = 'active' if s in active_services else 'inactive' + cmd.poutput("Checking service No %u (%s)" % (s, active_str)) + for f in files_by_service[s]: + should_exist = f.should_exist_for_services(active_services) + try: + (data, sw) = cmd.card._scc.select_file(f.fid) + exists = True + fcp = f.decode_select_response(data) + # if we just selected a directory, go back + if fcp['file_descriptor']['file_type'] == 'df': + cmd.card._scc.select_parent_df() + except SwMatchError as e: + sw = str(e) + exists = False + if exists != should_exist: + if exists: + cmd.poutput(" ERROR: File %s is selectable but should not!" % f) + else: + cmd.poutput(" ERROR: File %s is not selectable (%s) but should!" % (f, sw)) + finally: + # re-select the EF.UST + cmd.card._scc.select_file(self.fid) + +class EF_UST(EF_UServiceTable): + def __init__(self, **kwargs): + super().__init__(fid='6f38', sfid=0x04, name='EF.UST', desc='USIM Service Table', size={1,17}, table=EF_UST_map, **kwargs) + # add those commands to the general commands of a TransparentEF + self.shell_commands += [self.AddlShellCommands()] + @with_default_category('File-Specific Commands') class AddlShellCommands(CommandSet): def __init__(self): @@ -602,38 +641,8 @@ class EF_UServiceTable(TransparentEF): def do_ust_service_check(self, arg): """Check consistency between services of this file and files present/activated""" - # obtain list of currently active services - (service_data, sw) = self._cmd.rs.read_binary_dec() - for s in service_data.keys(): - if service_data[s]['activated']: - active_services.append(s) - # iterate over all the service-constraints we know of selected_file = self._cmd.rs.selected_file - files_by_service = selected_file.parent.files_by_service - try: - for s in sorted(files_by_service.keys()): - active_str = 'active' if s in active_services else 'inactive' - self._cmd.poutput("Checking service No %u (%s)" % (s, active_str)) - for f in files_by_service[s]: - should_exist = f.should_exist_for_services(active_services) - try: - (data, sw) = self._cmd.card._scc.select_file(f.fid) - exists = True - fcp = f.decode_select_response(data) - # if we just selected a directory, go back - if fcp['file_descriptor']['file_type'] == 'df': - self._cmd.card._scc.select_parent_df() - except SwMatchError as e: - sw = e.sw_actual - exists = False - if exists != should_exist: - if exists: - self._cmd.poutput(" ERROR: File %s is selectable but should not!" % f) - else: - self._cmd.poutput(" ERROR: File %s is not selectable (SW=%s) but should!" % (f, sw)) - finally: - # re-select the EF.UST - self._cmd.card._scc.select_file(selected_file.fid) + selected_file.ust_service_check(self._cmd) # TS 31.103 Section 4.2.7 - *not* the same as DF.GSM/EF.ECC! @@ -750,6 +759,33 @@ class EF_CCP2(LinFixedEF): def __init__(self, fid='6f4f', sfid=0x16, name='EF.CCP2', desc='Capability Configuration Parameters 2', **kwargs): super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len={15, None}, **kwargs) +# TS 31.102 Section 4.2.47 +class EF_EST(EF_UServiceTable): + def __init__(self, **kwargs): + super().__init__(fid='6f56', sfid=0x05, name='EF.EST', desc='Enabled Services Table', size={1,None}, table=EF_EST_map, **kwargs) + # add those commands to the general commands of a TransparentEF + self.shell_commands += [self.AddlShellCommands()] + + @with_default_category('File-Specific Commands') + class AddlShellCommands(CommandSet): + def __init__(self): + super().__init__() + + def do_est_service_activate(self, arg): + """Activate a service within EF.UST""" + self._cmd.card.update_est(int(arg), 1) + + def do_est_service_deactivate(self, arg): + """Deactivate a service within EF.UST""" + self._cmd.card.update_est(int(arg), 0) + + def do_est_service_check(self, arg): + """Check consistency between services of this file and files present/activated""" + # obtain list of currently active services + (service_data, sw) = self._cmd.rs.read_binary_dec() + active_services = service_data.keys() + + # TS 31.102 Section 4.2.48 class EF_ACL(TransparentEF): def __init__(self, fid='6f57', sfid=None, name='EF.ACL', size={32, None}, @@ -1128,8 +1164,7 @@ class ADF_USIM(CardADF): 'User controlled PLMN Selector with Access Technology', service=20), EF_HPPLMN(), EF_ACMmax(service=13), - EF_UServiceTable('6f38', 0x04, 'EF.UST', 'USIM Service Table', size={ - 1, 17}, table=EF_UST_map), + EF_UST(), CyclicEF('6f39', None, 'EF.ACM', 'Accumulated call meter', rec_len={3, 3}, service=13), TransparentEF('6f3e', None, 'EF.GID1', 'Group Identifier Level 1', service=17), @@ -1168,8 +1203,7 @@ class ADF_USIM(CardADF): EF_ADN('6f4d', None, 'EF.BDN', 'Barred Dialling Numbers', service=6), EF_EXT('6f55', None, 'EF.EXT4', 'Extension4 (BDN/SSC)', service=7), EF_CMI(service=6), - EF_UServiceTable('6f56', 0x05, 'EF.EST', 'Enabled Services Table', size={ - 1, None}, table=EF_EST_map, service=[2, 6, 34, 35]), + EF_EST(service=[2, 6, 34, 35]), EF_ACL(service=35), EF_DCK(service=36), EF_CNL(service=37), diff --git a/pySim/ts_31_103.py b/pySim/ts_31_103.py index 7d324091..f04f480e 100644 --- a/pySim/ts_31_103.py +++ b/pySim/ts_31_103.py @@ -104,6 +104,31 @@ class EF_IMPU(LinFixedEF): super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, **kwargs) self._tlv = EF_IMPU.impu +# TS 31.103 Section 4.2.7 +class EF_IST(EF_UServiceTable): + def __init__(self, **kwargs): + super().__init__('6f07', 0x07, 'EF.IST', 'ISIM Service Table', {1, None}, EF_IST_map) + # add those commands to the general commands of a TransparentEF + self.shell_commands += [self.AddlShellCommands()] + + @with_default_category('File-Specific Commands') + class AddlShellCommands(CommandSet): + def __init__(self): + super().__init__() + + def do_ist_service_activate(self, arg): + """Activate a service within EF.IST""" + self._cmd.card.update_ist(int(arg), 1) + + def do_ist_service_deactivate(self, arg): + """Deactivate a service within EF.IST""" + self._cmd.card.update_ist(int(arg), 0) + + def do_ist_service_check(self, arg): + """Check consistency between services of this file and files present/activated""" + selected_file = self._cmd.rs.selected_file + selected_file.ust_service_check(self._cmd) + # TS 31.103 Section 4.2.8 class EF_PCSCF(LinFixedEF): def __init__(self, fid='6f09', sfid=None, name='EF.P-CSCF', desc='P-CSCF Address', **kwargs): @@ -179,8 +204,7 @@ class ADF_ISIM(CardADF): EF_IMPU(), EF_AD(), EF_ARR('6f06', 0x06), - EF_UServiceTable('6f07', 0x07, 'EF.IST', - 'ISIM Service Table', {1, None}, EF_IST_map), + EF_IST(), EF_PCSCF(service=5), EF_GBABP(service=2), EF_GBANL(service=2),