laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/pysim/+/35953?usp=email )

Change subject: Add terminal_capability command to send TERMINAL CAPABILITY
......................................................................

Add terminal_capability command to send TERMINAL CAPABILITY

TS 102 221 specifies a TERMINAL CAPABILITY command using which the
terminal (Software + hardware talking to the card) can expose their
capabilities.  This is also used in the eUICC universe to let the eUICC
know which features are supported.

Change-Id: Iaeb8b4c34524edbb93217bf401e466399626e9b0
---
M docs/shell.rst
M pySim/ts_102_221.py
2 files changed, 136 insertions(+), 2 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/docs/shell.rst b/docs/shell.rst
index d86f500..487d22e 100644
--- a/docs/shell.rst
+++ b/docs/shell.rst
@@ -473,7 +473,18 @@
    :module: pySim.ts_102_221
    :func: CardProfileUICC.AddlShellCommands.resume_uicc_parser

+terminal_capability
+~~~~~~~~~~~~~~~~~~~
+This command allows you to perform the TERMINAL CAPABILITY command towards the 
card.

+TS 102 221 specifies the TERMINAL CAPABILITY command using which the
+terminal (Software + hardware talking to the card) can expose their
+capabilities.  This is also used in the eUICC universe to let the eUICC
+know which features are supported.
+
+.. argparse::
+   :module: pySim.ts_102_221
+   :func: CardProfileUICC.AddlShellCommands.term_cap_parser


 Linear Fixed EF commands
diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py
index 37b7856..1b40b09 100644
--- a/pySim/ts_102_221.py
+++ b/pySim/ts_102_221.py
@@ -1,7 +1,7 @@
 # coding=utf-8
 """Utilities / Functions related to ETSI TS 102 221, the core UICC spec.

-(C) 2021 by Harald Welte <[email protected]>
+(C) 2021-2024 by Harald Welte <[email protected]>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -80,6 +80,10 @@
     CardCommand('RESIZE FILE',              0xD4, ['8X', 'CX']),
 ])

+
+# ETSI TS 102 221 6.2.1
+SupplyVoltageClasses = FlagsEnum(Int8ub, a=0x1, b=0x2, c=0x4, d=0x8, e=0x10)
+
 # ETSI TS 102 221 11.1.1.4.2
 class FileSize(BER_TLV_IE, tag=0x80):
     _construct = GreedyInteger(minlen=2)
@@ -131,7 +135,7 @@

 # ETSI TS 102 221 11.1.1.4.6.2
 class ApplicationPowerConsumption(BER_TLV_IE, tag=0x81):
-    _construct = Struct('voltage_class'/Int8ub,
+    _construct = Struct('voltage_class'/SupplyVoltageClasses,
                         'power_consumption_ma'/Int8ub,
                         'reference_freq_100k'/Int8ub)

@@ -283,6 +287,33 @@
             return val
     return {d[0]: newval(inmap, d[0], d[1]) for d in indata.items()}

+# TS 102 221 11.1.19.2.1
+class TerminalPowerSupply(BER_TLV_IE, tag=0x80):
+    _construct = Struct('used_supply_voltage_class'/SupplyVoltageClasses,
+                        'maximum_available_power_supply'/Int8ub,
+                        'actual_used_freq_100k'/Int8ub)
+
+# TS 102 221 11.1.19.2.2
+class ExtendedLchanTerminalSupport(BER_TLV_IE, tag=0x81):
+    _construct = GreedyBytes
+
+# TS 102 221 11.1.19.2.3
+class AdditionalInterfacesSupport(BER_TLV_IE, tag=0x82):
+    _construct = FlagsEnum(Int8ub, uicc_clf=0x01)
+
+# TS 102 221 11.1.19.2.4 + SGP.32 v3.0 3.4.2 RSP Device Capabilities
+class AdditionalTermCapEuicc(BER_TLV_IE, tag=0x83):
+    _construct = FlagsEnum(Int8ub, lui_d=0x01, lpd_d=0x02, lds_d=0x04, 
lui_e_scws=0x08,
+                           metadata_update_alerting=0x10,
+                           enterprise_capable_device=0x20,
+                           lui_e_e4e=0x40,
+                           lpr=0x80)
+
+# TS 102 221 11.1.19.2.0
+class TerminalCapability(BER_TLV_IE, tag=0xa9, nested=[TerminalPowerSupply, 
ExtendedLchanTerminalSupport,
+                                                       
AdditionalInterfacesSupport, AdditionalTermCapEuicc]):
+    pass
+
 # ETSI TS 102 221 Section 9.2.7 + ISO7816-4 9.3.3/9.3.4
 class _AM_DO_DF(DataObject):
     def __init__(self):
@@ -901,3 +932,81 @@
             of the card is required between SUSPEND and RESUME, and only very 
few non-RESUME
             commands are permitted between SUSPEND and RESUME.  See TS 102 221 
Section 11.1.22."""
             self._cmd.card._scc.resume_uicc(opts.token)
+
+        term_cap_parser = argparse.ArgumentParser()
+        # power group
+        tc_power_grp = term_cap_parser.add_argument_group('Terminal Power 
Supply')
+        tc_power_grp.add_argument('--used-supply-voltage-class', type=str, 
choices=['a','b','c','d','e'],
+                                  help='Actual used Supply voltage class')
+        tc_power_grp.add_argument('--maximum-available-power-supply', 
type=auto_uint8,
+                                  help='Maximum available power supply of the 
terminal')
+        tc_power_grp.add_argument('--actual-used-freq-100k', type=auto_uint8,
+                                  help='Actual used clock frequency (in units 
of 100kHz)')
+        # no separate groups for those two
+        tc_elc_grp = term_cap_parser.add_argument_group('Extended logical 
channels terminal support')
+        tc_elc_grp.add_argument('--extended-logical-channel', 
action='store_true',
+                                help='Extended Logical Channel supported')
+        tc_aif_grp = term_cap_parser.add_argument_group('Additional interfaces 
support')
+        tc_aif_grp.add_argument('--uicc-clf', action='store_true',
+                                help='Local User Interface in the Device 
(LUId) supported')
+        # eUICC group
+        tc_euicc_grp = term_cap_parser.add_argument_group('Additional Terminal 
capability indications related to eUICC')
+        tc_euicc_grp.add_argument('--lui-d', action='store_true',
+                                  help='Local User Interface in the Device 
(LUId) supported')
+        tc_euicc_grp.add_argument('--lpd-d', action='store_true',
+                                  help='Local Profile Download in the Device 
(LPDd) supported')
+        tc_euicc_grp.add_argument('--lds-d', action='store_true',
+                                  help='Local Discovery Service in the Device 
(LPDd) supported')
+        tc_euicc_grp.add_argument('--lui-e-scws', action='store_true',
+                                  help='LUIe based on SCWS supported')
+        tc_euicc_grp.add_argument('--metadata-update-alerting', 
action='store_true',
+                                  help='Metadata update alerting supported')
+        tc_euicc_grp.add_argument('--enterprise-capable-device', 
action='store_true',
+                                  help='Enterprise Capable Device')
+        tc_euicc_grp.add_argument('--lui-e-e4e', action='store_true',
+                                  help='LUIe using E4E (ENVELOPE tag E4) 
supported')
+        tc_euicc_grp.add_argument('--lpr', action='store_true',
+                                  help='LPR (LPA Proxy) supported')
+
+        @cmd2.with_argparser(term_cap_parser)
+        def do_terminal_capability(self, opts):
+            """Perform the TERMINAL CAPABILITY function. Used to inform the 
UICC about terminal capability."""
+            ps_flags = {}
+            addl_if_flags = {}
+            euicc_flags = {}
+
+            opts_dict = vars(opts)
+
+            power_items = ['used_supply_voltage_class', 
'maximum_available_power_supply', 'actual_used_freq_100k']
+            if any(opts_dict[x] for x in power_items):
+                if not all(opts_dict[x] for x in power_items):
+                    raise argparse.ArgumentTypeError('If any of the Terminal 
Power Supply group options are used, all must be specified')
+
+            for k, v in opts_dict.items():
+                if k in AdditionalInterfacesSupport._construct.flags.keys():
+                    addl_if_flags[k] = v
+                elif k in AdditionalTermCapEuicc._construct.flags.keys():
+                    euicc_flags[k] = v
+                elif k in [f.name for f in 
TerminalPowerSupply._construct.subcons]:
+                    if k == 'used_supply_voltage_class' and v:
+                        v = {v: True}
+                    ps_flags[k] = v
+
+            child_list = []
+            if any(x for x in ps_flags.values()):
+                child_list.append(TerminalPowerSupply(decoded=ps_flags))
+
+            if opts.extended_logical_channel:
+                child_list.append(ExtendedLchanTerminalSupport())
+            if any(x for x in addl_if_flags.values()):
+                
child_list.append(AdditionalInterfacesSupport(decoded=addl_if_flags))
+            if any(x for x in euicc_flags.values()):
+                child_list.append(AdditionalTermCapEuicc(decoded=euicc_flags))
+
+            print(child_list)
+            tc = TerminalCapability(children=child_list)
+            self.terminal_capability(b2h(tc.to_tlv()))
+
+        def terminal_capability(self, data:Hexstr):
+            cmd_hex = "80AA0000%02x%s" % (len(data)//2, data)
+            _rsp_hex, _sw = self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/35953?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Iaeb8b4c34524edbb93217bf401e466399626e9b0
Gerrit-Change-Number: 35953
Gerrit-PatchSet: 3
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-CC: fixeria <[email protected]>
Gerrit-MessageType: merged

Reply via email to