mirror of https://gerrit.osmocom.org/pysim
Introduce concept of CardProfileAddon
We have a strict "one CardProfile per card" rule. For a modern UICC without legacy SIM support, that works great, as all applications have AID and ADF and can hence be enumerated/detected that way. However, in reality there are mostly UICC that have legacy SIM, GSM-R or even CDMA support, all of which are not proper UICC applications for historical reasons. So instead of having hard-coded hacks in various places, let's introduce the new concept of a CardProfileAddon. Every profile can have any number of those. When building up the RuntimeState, we iterate over the CardProfile addons, and probe which of those are actually on the card. For those discovered, we add their files to the filesystem hierarchy. Change-Id: I5866590b6d48f85eb889c9b1b8ab27936d2378b9
This commit is contained in:
parent
f9e2df1296
commit
323a35043f
|
@ -137,11 +137,6 @@ def init_card(sl):
|
|||
# Create runtime state with card profile
|
||||
rs = RuntimeState(card, profile)
|
||||
|
||||
# FIXME: This is an GSM-R related file, it needs to be added throughout,
|
||||
# the profile. At the moment we add it for all cards, this won't hurt,
|
||||
# but regular SIM and UICC will not have it and fail to select it.
|
||||
rs.mf.add_file(DF_EIRENE())
|
||||
|
||||
CardModel.apply_matching_models(scc, rs)
|
||||
|
||||
# inform the transport that we can do context-specific SW interpretation
|
||||
|
|
|
@ -11,7 +11,7 @@ from pySim.filesystem import RuntimeState
|
|||
from pySim.cards import UiccCardBase
|
||||
from pySim.commands import SimCardCommands
|
||||
from pySim.profile import CardProfile
|
||||
from pySim.ts_102_221 import CardProfileUICCSIM
|
||||
from pySim.ts_102_221 import CardProfileUICC
|
||||
from pySim.ts_31_102 import CardApplicationUSIM
|
||||
from pySim.ts_31_103 import CardApplicationISIM
|
||||
from pySim.transport import LinkBase
|
||||
|
@ -70,8 +70,9 @@ class DummySimLink(LinkBase):
|
|||
|
||||
class Tracer:
|
||||
def __init__(self, **kwargs):
|
||||
# we assume a generic SIM + UICC + USIM + ISIM card
|
||||
profile = CardProfileUICCSIM()
|
||||
# we assume a generic UICC profile; as all APDUs return 9000 in DummySimLink above,
|
||||
# all CardProfileAddon (including SIM) will probe successful.
|
||||
profile = CardProfileUICC()
|
||||
profile.add_application(CardApplicationUSIM())
|
||||
profile.add_application(CardApplicationISIM())
|
||||
scc = SimCardCommands(transport=DummySimLink())
|
||||
|
|
|
@ -22,7 +22,7 @@ import enum
|
|||
from pySim.utils import *
|
||||
from pySim.filesystem import *
|
||||
from pySim.profile import match_ruim
|
||||
from pySim.profile import CardProfile
|
||||
from pySim.profile import CardProfile, CardProfileAddon
|
||||
from pySim.ts_51_011 import CardProfileSIM
|
||||
from pySim.ts_51_011 import DF_TELECOM, DF_GSM
|
||||
from pySim.ts_51_011 import EF_ServiceTable
|
||||
|
@ -191,3 +191,14 @@ class CardProfileRUIM(CardProfile):
|
|||
@staticmethod
|
||||
def match_with_card(scc: SimCardCommands) -> bool:
|
||||
return match_ruim(scc)
|
||||
|
||||
class AddonRUIM(CardProfileAddon):
|
||||
"""An Addon that can be found on on a combined SIM + RUIM or UICC + RUIM to support CDMA."""
|
||||
def __init__(self):
|
||||
files = [
|
||||
DF_CDMA()
|
||||
]
|
||||
super().__init__('RUIM', desc='CDMA RUIM', files_in_mf=files)
|
||||
|
||||
def probe(self, card: 'CardBase') -> bool:
|
||||
return card.file_exists(self.files_in_mf[0].fid)
|
||||
|
|
|
@ -1307,6 +1307,16 @@ class RuntimeState:
|
|||
self.card.set_apdu_parameter(
|
||||
cla=self.profile.cla, sel_ctrl=self.profile.sel_ctrl)
|
||||
|
||||
for addon_cls in self.profile.addons:
|
||||
addon = addon_cls()
|
||||
if addon.probe(self.card):
|
||||
print("Detected %s Add-on \"%s\"" % (self.profile, addon))
|
||||
for f in addon.files_in_mf:
|
||||
self.mf.add_file(f)
|
||||
|
||||
# go back to MF before the next steps (addon probing might have changed DF)
|
||||
self.card._scc.select_file('3F00')
|
||||
|
||||
# add application ADFs + MF-files from profile
|
||||
apps = self._match_applications()
|
||||
for a in apps:
|
||||
|
|
|
@ -35,8 +35,8 @@ from construct import Optional as COptional
|
|||
from pySim.construct import *
|
||||
import enum
|
||||
|
||||
from pySim.profile import CardProfileAddon
|
||||
from pySim.filesystem import *
|
||||
import pySim.ts_102_221
|
||||
import pySim.ts_51_011
|
||||
|
||||
######################################################################
|
||||
|
@ -362,3 +362,15 @@ class DF_EIRENE(CardDF):
|
|||
desc='Free Number Call Type 0 and 8'),
|
||||
]
|
||||
self.add_files(files)
|
||||
|
||||
|
||||
class AddonGSMR(CardProfileAddon):
|
||||
"""An Addon that can be found on either classic GSM SIM or on UICC to support GSM-R."""
|
||||
def __init__(self):
|
||||
files = [
|
||||
DF_EIRENE()
|
||||
]
|
||||
super().__init__('GSM-R', desc='Railway GSM', files_in_mf=files)
|
||||
|
||||
def probe(self, card: 'CardBase') -> bool:
|
||||
return card.file_exists(self.files_in_mf[0].fid)
|
||||
|
|
|
@ -88,6 +88,7 @@ class CardProfile:
|
|||
shell_cmdsets : List of cmd2 shell command sets of profile-specific commands
|
||||
cla : class byte that should be used with cards of this profile
|
||||
sel_ctrl : selection control bytes class byte that should be used with cards of this profile
|
||||
addons: List of optional CardAddons that a card of this profile might have
|
||||
"""
|
||||
self.name = name
|
||||
self.desc = kw.get("desc", None)
|
||||
|
@ -97,6 +98,8 @@ class CardProfile:
|
|||
self.shell_cmdsets = kw.get("shell_cmdsets", [])
|
||||
self.cla = kw.get("cla", "00")
|
||||
self.sel_ctrl = kw.get("sel_ctrl", "0004")
|
||||
# list of optional addons that a card of this profile might have
|
||||
self.addons = kw.get("addons", [])
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -161,3 +164,34 @@ class CardProfile:
|
|||
return p()
|
||||
|
||||
return None
|
||||
|
||||
def add_addon(self, addon: 'CardProfileAddon'):
|
||||
assert(addon not in self.addons)
|
||||
# we don't install any additional files, as that is happening in the RuntimeState.
|
||||
self.addons.append(addon)
|
||||
|
||||
class CardProfileAddon(abc.ABC):
|
||||
"""A Card Profile Add-on is something that is not a card application or a full stand-alone
|
||||
card profile, but an add-on to an existing profile. Think of GSM-R specific files existing
|
||||
on what is otherwise a SIM or USIM+SIM card."""
|
||||
|
||||
def __init__(self, name: str, **kw):
|
||||
"""
|
||||
Args:
|
||||
desc (str) : Description
|
||||
files_in_mf : List of CardEF instances present in MF
|
||||
shell_cmdsets : List of cmd2 shell command sets of profile-specific commands
|
||||
"""
|
||||
self.name = name
|
||||
self.desc = kw.get("desc", None)
|
||||
self.files_in_mf = kw.get("files_in_mf", [])
|
||||
self.shell_cmdsets = kw.get("shell_cmdsets", [])
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@abc.abstractmethod
|
||||
def probe(self, card: 'CardBase') -> bool:
|
||||
"""Probe a given card to determine whether or not this add-on is present/supported."""
|
||||
pass
|
||||
|
|
|
@ -31,7 +31,9 @@ import pySim.iso7816_4 as iso7816_4
|
|||
|
||||
# A UICC will usually also support 2G functionality. If this is the case, we
|
||||
# need to add DF_GSM and DF_TELECOM along with the UICC related files
|
||||
from pySim.ts_51_011 import DF_GSM, DF_TELECOM
|
||||
from pySim.ts_51_011 import DF_GSM, DF_TELECOM, AddonSIM
|
||||
from pySim.gsm_r import AddonGSMR
|
||||
from pySim.cdma_ruim import AddonRUIM
|
||||
|
||||
ts_102_22x_cmdset = CardCommandSet('TS 102 22x', [
|
||||
# TS 102 221 Section 10.1.2 Table 10.5 "Coding of Instruction Byte"
|
||||
|
@ -768,6 +770,11 @@ class CardProfileUICC(CardProfile):
|
|||
# FIXME: DF.CD
|
||||
EF_UMPC(),
|
||||
]
|
||||
addons = [
|
||||
AddonSIM,
|
||||
AddonGSMR,
|
||||
AddonRUIM,
|
||||
]
|
||||
sw = {
|
||||
'Normal': {
|
||||
'9000': 'Normal ending of the command',
|
||||
|
@ -839,7 +846,7 @@ class CardProfileUICC(CardProfile):
|
|||
|
||||
super().__init__(name, desc='ETSI TS 102 221', cla="00",
|
||||
sel_ctrl="0004", files_in_mf=files, sw=sw,
|
||||
shell_cmdsets = [self.AddlShellCommands()])
|
||||
shell_cmdsets = [self.AddlShellCommands()], addons = addons)
|
||||
|
||||
@staticmethod
|
||||
def decode_select_response(resp_hex: str) -> object:
|
||||
|
@ -895,4 +902,5 @@ class CardProfileUICCSIM(CardProfileUICC):
|
|||
|
||||
@staticmethod
|
||||
def match_with_card(scc: SimCardCommands) -> bool:
|
||||
return match_uicc(scc) and match_sim(scc)
|
||||
# don't ever select this profile, we only use this from pySim-trace
|
||||
return False
|
||||
|
|
|
@ -30,9 +30,10 @@ order to describe the files specified in the relevant ETSI + 3GPP specifications
|
|||
#
|
||||
|
||||
from pySim.profile import match_sim
|
||||
from pySim.profile import CardProfile
|
||||
from pySim.profile import CardProfile, CardProfileAddon
|
||||
from pySim.filesystem import *
|
||||
from pySim.ts_31_102_telecom import DF_PHONEBOOK, DF_MULTIMEDIA, DF_MCS, DF_V2X
|
||||
from pySim.gsm_r import AddonGSMR
|
||||
import enum
|
||||
from pySim.construct import *
|
||||
from construct import Optional as COptional
|
||||
|
@ -1047,8 +1048,12 @@ class CardProfileSIM(CardProfile):
|
|||
},
|
||||
}
|
||||
|
||||
addons = [
|
||||
AddonGSMR,
|
||||
]
|
||||
|
||||
super().__init__('SIM', desc='GSM SIM Card', cla="a0",
|
||||
sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw)
|
||||
sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw, addons = addons)
|
||||
|
||||
@staticmethod
|
||||
def decode_select_response(resp_hex: str) -> object:
|
||||
|
@ -1104,3 +1109,17 @@ class CardProfileSIM(CardProfile):
|
|||
@staticmethod
|
||||
def match_with_card(scc: SimCardCommands) -> bool:
|
||||
return match_sim(scc)
|
||||
|
||||
|
||||
class AddonSIM(CardProfileAddon):
|
||||
"""An add-on that can be found on a UICC in order to support classic GSM SIM."""
|
||||
def __init__(self):
|
||||
files = [
|
||||
DF_GSM(),
|
||||
DF_TELECOM(),
|
||||
]
|
||||
super().__init__('SIM', desc='GSM SIM', files_in_mf=files)
|
||||
|
||||
def probe(self, card:'CardBase') -> bool:
|
||||
# we assume the add-on to be present in case DF.GSM is found on the card
|
||||
return card.file_exists(self.files_in_mf[0].fid)
|
||||
|
|
Loading…
Reference in New Issue