laforge has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/34847?usp=email )


Change subject: pySim-shell: Create + use per-RuntimeLchan SimCardCommands
......................................................................

pySim-shell: Create + use per-RuntimeLchan SimCardCommands

This new approach will "fork" separate SimCardCommands instances
for each RuntimeLchan.  Higher-layer code should now always use the
RuntimeLchan.scc rather than the RuntimeState.card._scc in order to
make sure commands use the correct logical channel.

Change-Id: I13e2e871f2afc2460d9fd1cd566de42267c7d389
Related: OS#6230
---
M pySim-shell.py
M pySim/ara_m.py
M pySim/global_platform.py
M pySim/runtime.py
M pySim/ts_102_222.py
M pySim/ts_31_102.py
M pySim/ts_51_011.py
7 files changed, 59 insertions(+), 43 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/47/34847/1

diff --git a/pySim-shell.py b/pySim-shell.py
index 867795c..8a1ad01 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -326,7 +326,7 @@
         DANGEROUS: pySim-shell will not know any card state changes, and
         not continue to work as expected if you e.g. select a different
         file."""
-        data, sw = self.card._scc._tp.send_apdu(opts.APDU)
+        data, sw = self.lchan.scc._tp.send_apdu(opts.APDU)
         if data:
             self.poutput("SW: %s, RESP: %s" % (sw, data))
         else:
@@ -790,7 +790,7 @@
                     "cannot find ADM-PIN for ICCID '%s'" % (self._cmd.iccid))

         if pin_adm:
-            self._cmd.card._scc.verify_chv(self._cmd.card._adm_chv_num, 
h2b(pin_adm))
+            self._cmd.lchan.scc.verify_chv(self._cmd.card._adm_chv_num, 
h2b(pin_adm))
         else:
             raise ValueError("error: cannot authenticate, no adm-pin!")

@@ -798,10 +798,10 @@
         """Display information about the currently inserted card"""
         self._cmd.poutput("Card info:")
         self._cmd.poutput(" Name: %s" % self._cmd.card.name)
-        self._cmd.poutput(" ATR: %s" % b2h(self._cmd.card._scc.get_atr()))
+        self._cmd.poutput(" ATR: %s" % b2h(self._cmd.lchan.scc.get_atr()))
         self._cmd.poutput(" ICCID: %s" % self._cmd.iccid)
-        self._cmd.poutput(" Class-Byte: %s" % self._cmd.card._scc.cla_byte)
-        self._cmd.poutput(" Select-Ctrl: %s" % self._cmd.card._scc.sel_ctrl)
+        self._cmd.poutput(" Class-Byte: %s" % self._cmd.lchan.scc.cla_byte)
+        self._cmd.poutput(" Select-Ctrl: %s" % self._cmd.lchan.scc.sel_ctrl)
         self._cmd.poutput(" AIDs:")
         for a in self._cmd.rs.mf.applications:
                 self._cmd.poutput("  %s" % a)
@@ -859,7 +859,7 @@
         call it if you authenticate yourself using the specified PIN.  There 
usually is at least PIN1 and
         PIN2."""
         pin = self.get_code(opts.pin_code)
-        (data, sw) = self._cmd.card._scc.verify_chv(opts.pin_nr, h2b(pin))
+        (data, sw) = self._cmd.lchan.scc.verify_chv(opts.pin_nr, h2b(pin))
         self._cmd.poutput("CHV verification successful")

     unblock_chv_parser = argparse.ArgumentParser()
@@ -875,7 +875,7 @@
         """Unblock PIN code using specified PUK code"""
         new_pin = self.get_code(opts.new_pin_code)
         puk = self.get_code(opts.puk_code)
-        (data, sw) = self._cmd.card._scc.unblock_chv(
+        (data, sw) = self._cmd.lchan.scc.unblock_chv(
             opts.pin_nr, h2b(puk), h2b(new_pin))
         self._cmd.poutput("CHV unblock successful")

@@ -892,7 +892,7 @@
         """Change PIN code to a new PIN code"""
         new_pin = self.get_code(opts.new_pin_code)
         pin = self.get_code(opts.pin_code)
-        (data, sw) = self._cmd.card._scc.change_chv(
+        (data, sw) = self._cmd.lchan.scc.change_chv(
             opts.pin_nr, h2b(pin), h2b(new_pin))
         self._cmd.poutput("CHV change successful")

@@ -906,7 +906,7 @@
     def do_disable_chv(self, opts):
         """Disable PIN code using specified PIN code"""
         pin = self.get_code(opts.pin_code)
-        (data, sw) = self._cmd.card._scc.disable_chv(opts.pin_nr, h2b(pin))
+        (data, sw) = self._cmd.lchan.scc.disable_chv(opts.pin_nr, h2b(pin))
         self._cmd.poutput("CHV disable successful")

     enable_chv_parser = argparse.ArgumentParser()
@@ -919,12 +919,12 @@
     def do_enable_chv(self, opts):
         """Enable PIN code using specified PIN code"""
         pin = self.get_code(opts.pin_code)
-        (data, sw) = self._cmd.card._scc.enable_chv(opts.pin_nr, h2b(pin))
+        (data, sw) = self._cmd.lchan.scc.enable_chv(opts.pin_nr, h2b(pin))
         self._cmd.poutput("CHV enable successful")

     def do_deactivate_file(self, opts):
         """Deactivate the currently selected EF"""
-        (data, sw) = self._cmd.card._scc.deactivate_file()
+        (data, sw) = self._cmd.lchan.scc.deactivate_file()

     activate_file_parser = argparse.ArgumentParser()
     activate_file_parser.add_argument('NAME', type=str, help='File name or FID 
of file to activate')
@@ -946,7 +946,7 @@
     @cmd2.with_argparser(open_chan_parser)
     def do_open_channel(self, opts):
         """Open a logical channel."""
-        (data, sw) = self._cmd.card._scc.manage_channel(
+        (data, sw) = self._cmd.lchan.scc.manage_channel(
             mode='open', lchan_nr=opts.chan_nr)
         # this is executed only in successful case, as unsuccessful raises 
exception
         self._cmd.lchan.add_lchan(opts.chan_nr)
@@ -958,7 +958,7 @@
     @cmd2.with_argparser(close_chan_parser)
     def do_close_channel(self, opts):
         """Close a logical channel."""
-        (data, sw) = self._cmd.card._scc.manage_channel(
+        (data, sw) = self._cmd.lchan.scc.manage_channel(
             mode='close', lchan_nr=opts.chan_nr)
         # this is executed only in successful case, as unsuccessful raises 
exception
         self._cmd.rs.del_lchan(opts.chan_nr)
diff --git a/pySim/ara_m.py b/pySim/ara_m.py
index 8144381..b4ac747 100644
--- a/pySim/ara_m.py
+++ b/pySim/ara_m.py
@@ -306,13 +306,13 @@

         def do_aram_get_all(self, opts):
             """GET DATA [All] on the ARA-M Applet"""
-            res_do = ADF_ARAM.get_all(self._cmd.card._scc._tp)
+            res_do = ADF_ARAM.get_all(self._cmd.lchan.scc._tp)
             if res_do:
                 self._cmd.poutput_json(res_do.to_dict())

         def do_aram_get_config(self, opts):
             """Perform GET DATA [Config] on the ARA-M Applet: Tell it our 
version and retrieve its version."""
-            res_do = ADF_ARAM.get_config(self._cmd.card._scc._tp)
+            res_do = ADF_ARAM.get_config(self._cmd.lchan.scc._tp)
             if res_do:
                 self._cmd.poutput_json(res_do.to_dict())

@@ -373,14 +373,14 @@
             d = [{'ref_ar_do': [{'ref_do': ref_do_content}, {'ar_do': 
ar_do_content}]}]
             csrado = CommandStoreRefArDO()
             csrado.from_dict(d)
-            res_do = ADF_ARAM.store_data(self._cmd.card._scc._tp, csrado)
+            res_do = ADF_ARAM.store_data(self._cmd.lchan.scc._tp, csrado)
             if res_do:
                 self._cmd.poutput_json(res_do.to_dict())

         def do_aram_delete_all(self, opts):
             """Perform STORE DATA [Command-Delete[all]] to delete all access 
rules."""
             deldo = CommandDelete()
-            res_do = ADF_ARAM.store_data(self._cmd.card._scc._tp, deldo)
+            res_do = ADF_ARAM.store_data(self._cmd.lchan.scc._tp, deldo)
             if res_do:
                 self._cmd.poutput_json(res_do.to_dict())

diff --git a/pySim/global_platform.py b/pySim/global_platform.py
index ea8b70d..bfa2adf 100644
--- a/pySim/global_platform.py
+++ b/pySim/global_platform.py
@@ -238,7 +238,7 @@
                 self._cmd.poutput('Unknown data object "%s", available 
options: %s' % (tlv_cls_name,
                                                                                
        do_names))
                 return
-            (data, sw) = self._cmd.card._scc.get_data(cla=0x80, 
tag=tlv_cls.tag)
+            (data, sw) = self._cmd.lchan.scc.get_data(cla=0x80, 
tag=tlv_cls.tag)
             ie = tlv_cls()
             ie.from_tlv(h2b(data))
             self._cmd.poutput_json(ie.to_dict())
diff --git a/pySim/runtime.py b/pySim/runtime.py
index 88de69e..27c2ef1 100644
--- a/pySim/runtime.py
+++ b/pySim/runtime.py
@@ -167,6 +167,7 @@
         self.selected_adf = None
         self.selected_file_fcp = None
         self.selected_file_fcp_hex = None
+        self.scc = self.rs.card._scc.fork_lchan(lchan_nr)

     def add_lchan(self, lchan_nr: int) -> 'RuntimeLchan':
         """Add a new logical channel from the current logical channel. Just 
affects
@@ -246,7 +247,7 @@
                 "Cannot select unknown file by name %s, only hexadecimal 4 
digit FID is allowed" % fid)

         try:
-            (data, sw) = self.rs.card._scc.select_file(fid)
+            (data, sw) = self.scc.select_file(fid)
         except SwMatchError as swm:
             k = self.interpret_sw(swm.sw_actual)
             if not k:
@@ -301,7 +302,7 @@
                     (data, sw) = self.rs.card.select_adf_by_aid(p.aid)
                     self.selected_adf = p
                 else:
-                    (data, sw) = self.rs.card._scc.select_file(p.fid)
+                    (data, sw) = self.scc.select_file(p.fid)
                 self.selected_file = p
             except SwMatchError as swm:
                 self._select_post(cmd_app)
@@ -344,7 +345,7 @@
                 if isinstance(f, CardADF):
                     (data, sw) = self.rs.card.select_adf_by_aid(f.aid)
                 else:
-                    (data, sw) = self.rs.card._scc.select_file(f.fid)
+                    (data, sw) = self.scc.select_file(f.fid)
                 self.selected_file = f
             except SwMatchError as swm:
                 k = self.interpret_sw(swm.sw_actual)
@@ -364,7 +365,7 @@

     def status(self):
         """Request STATUS (current selected file FCP) from card."""
-        (data, sw) = self.rs.card._scc.status()
+        (data, sw) = self.scc.status()
         return self.selected_file.decode_select_response(data)

     def get_file_for_selectable(self, name: str):
@@ -375,7 +376,7 @@
         """Request ACTIVATE FILE of specified file."""
         sels = self.selected_file.get_selectables()
         f = sels[name]
-        data, sw = self.rs.card._scc.activate_file(f.fid)
+        data, sw = self.scc.activate_file(f.fid)
         return data, sw

     def read_binary(self, length: int = None, offset: int = 0):
@@ -389,7 +390,7 @@
         """
         if not isinstance(self.selected_file, TransparentEF):
             raise TypeError("Only works with TransparentEF")
-        return self.rs.card._scc.read_binary(self.selected_file.fid, length, 
offset)
+        return self.scc.read_binary(self.selected_file.fid, length, offset)

     def read_binary_dec(self) -> Tuple[dict, str]:
         """Read [part of] a transparent EF binary data and decode it.
@@ -413,7 +414,7 @@
         """
         if not isinstance(self.selected_file, TransparentEF):
             raise TypeError("Only works with TransparentEF")
-        return self.rs.card._scc.update_binary(self.selected_file.fid, 
data_hex, offset, conserve=self.rs.conserve_write)
+        return self.scc.update_binary(self.selected_file.fid, data_hex, 
offset, conserve=self.rs.conserve_write)

     def update_binary_dec(self, data: dict):
         """Update transparent EF from abstract data. Encodes the data to 
binary and
@@ -436,7 +437,7 @@
         if not isinstance(self.selected_file, LinFixedEF):
             raise TypeError("Only works with Linear Fixed EF")
         # returns a string of hex nibbles
-        return self.rs.card._scc.read_record(self.selected_file.fid, rec_nr)
+        return self.scc.read_record(self.selected_file.fid, rec_nr)
 
     def read_record_dec(self, rec_nr: int = 0) -> Tuple[dict, str]:
         """Read a record and decode it to abstract data.
@@ -458,7 +459,7 @@
         """
         if not isinstance(self.selected_file, LinFixedEF):
             raise TypeError("Only works with Linear Fixed EF")
-        return self.rs.card._scc.update_record(self.selected_file.fid, rec_nr, 
data_hex,
+        return self.scc.update_record(self.selected_file.fid, rec_nr, data_hex,
                                               conserve=self.rs.conserve_write,
                                               
leftpad=self.selected_file.leftpad)

@@ -484,7 +485,7 @@
         if not isinstance(self.selected_file, BerTlvEF):
             raise TypeError("Only works with BER-TLV EF")
         # returns a string of hex nibbles
-        return self.rs.card._scc.retrieve_data(self.selected_file.fid, tag)
+        return self.scc.retrieve_data(self.selected_file.fid, tag)

     def retrieve_tags(self):
         """Retrieve tags available on BER-TLV EF.
@@ -494,7 +495,7 @@
         """
         if not isinstance(self.selected_file, BerTlvEF):
             raise TypeError("Only works with BER-TLV EF")
-        data, sw = self.rs.card._scc.retrieve_data(self.selected_file.fid, 
0x5c)
+        data, sw = self.scc.retrieve_data(self.selected_file.fid, 0x5c)
         tag, length, value, remainder = bertlv_parse_one(h2b(data))
         return list(value)

@@ -507,7 +508,7 @@
         """
         if not isinstance(self.selected_file, BerTlvEF):
             raise TypeError("Only works with BER-TLV EF")
-        return self.rs.card._scc.set_data(self.selected_file.fid, tag, 
data_hex, conserve=self.rs.conserve_write)
+        return self.scc.set_data(self.selected_file.fid, tag, data_hex, 
conserve=self.rs.conserve_write)

     def unregister_cmds(self, cmd_app=None):
         """Unregister all file specific commands."""
diff --git a/pySim/ts_102_222.py b/pySim/ts_102_222.py
index a4ea453..372d67f 100644
--- a/pySim/ts_102_222.py
+++ b/pySim/ts_102_222.py
@@ -49,7 +49,7 @@
             self._cmd.perror("Refusing to permanently delete the file, please 
read the help text.")
             return
         f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
-        (data, sw) = self._cmd.card._scc.delete_file(f.fid)
+        (data, sw) = self._cmd.lchan.scc.delete_file(f.fid)

     def complete_delete_file(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for DELETE FILE"""
@@ -70,7 +70,7 @@
             self._cmd.perror("Refusing to terminate the file, please read the 
help text.")
             return
         f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
-        (data, sw) = self._cmd.card._scc.terminate_df(f.fid)
+        (data, sw) = self._cmd.lchan.scc.terminate_df(f.fid)

     def complete_terminate_df(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for TERMINATE DF"""
@@ -86,7 +86,7 @@
             self._cmd.perror("Refusing to terminate the file, please read the 
help text.")
             return
         f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
-        (data, sw) = self._cmd.card._scc.terminate_ef(f.fid)
+        (data, sw) = self._cmd.lchan.scc.terminate_ef(f.fid)

     def complete_terminate_ef(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for TERMINATE EF"""
@@ -104,7 +104,7 @@
         if not opts.force_terminate_card:
             self._cmd.perror("Refusing to permanently terminate the card, 
please read the help text.")
             return
-        (data, sw) = self._cmd.card._scc.terminate_card_usage()
+        (data, sw) = self._cmd.lchan.scc.terminate_card_usage()

     create_parser = argparse.ArgumentParser()
     create_parser.add_argument('FILE_ID', type=str, help='File Identifier as 
4-character hex string')
@@ -149,7 +149,7 @@
                ShortFileIdentifier(decoded=opts.short_file_id),
             ]
         fcp = FcpTemplate(children=ies)
-        (data, sw) = self._cmd.card._scc.create_file(b2h(fcp.to_tlv()))
+        (data, sw) = self._cmd.lchan.scc.create_file(b2h(fcp.to_tlv()))
         # the newly-created file is automatically selected but our runtime 
state knows nothing of it
         self._cmd.lchan.select_file(self._cmd.lchan.selected_file)

@@ -200,7 +200,7 @@
                    }
                
ies.append(ProprietaryInformation(children=[ToolkitAccessConditions(decoded=toolkit_ac)]))
         fcp = FcpTemplate(children=ies)
-        (data, sw) = self._cmd.card._scc.create_file(b2h(fcp.to_tlv()))
+        (data, sw) = self._cmd.lchan.scc.create_file(b2h(fcp.to_tlv()))
         # the newly-created file is automatically selected but our runtime 
state knows nothing of it
         self._cmd.lchan.select_file(self._cmd.lchan.selected_file)

@@ -217,7 +217,7 @@
         ies = [FileIdentifier(decoded=f.fid),
                FileSize(decoded=opts.file_size)]
         fcp = FcpTemplate(children=ies)
-        (data, sw) = self._cmd.card._scc.resize_file(b2h(fcp.to_tlv()))
+        (data, sw) = self._cmd.lchan.scc.resize_file(b2h(fcp.to_tlv()))
         # the resized file is automatically selected but our runtime state 
knows nothing of it
         self._cmd.lchan.select_file(self._cmd.lchan.selected_file)

diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py
index 54ff4c8..cd0d99c 100644
--- a/pySim/ts_31_102.py
+++ b/pySim/ts_31_102.py
@@ -1512,7 +1512,7 @@
         @cmd2.with_argparser(authenticate_parser)
         def do_authenticate(self, opts):
             """Perform Authentication and Key Agreement (AKA)."""
-            (data, sw) = self._cmd.card._scc.authenticate(opts.rand, opts.autn)
+            (data, sw) = self._cmd.lchan.scc.authenticate(opts.rand, opts.autn)
             self._cmd.poutput_json(data)

         term_prof_parser = argparse.ArgumentParser()
@@ -1526,7 +1526,7 @@
             in the context of SIM Toolkit, Proactive SIM and OTA.  You
             must specify a hex-string with the encoded terminal profile
             you want to send to the card."""
-            (data, sw) = self._cmd.card._scc.terminal_profile(opts.PROFILE)
+            (data, sw) = self._cmd.lchan.scc.terminal_profile(opts.PROFILE)
             self._cmd.poutput('SW: %s, data: %s' % (sw, data))

         envelope_parser = argparse.ArgumentParser()
@@ -1538,7 +1538,7 @@
             variety of information is communicated from the terminal
             (modem/phone) to the card, particularly in the context of
             SIM Toolkit, Proactive SIM and OTA."""
-            (data, sw) = self._cmd.card._scc.envelope(opts.PAYLOAD)
+            (data, sw) = self._cmd.lchan.scc.envelope(opts.PAYLOAD)
             self._cmd.poutput('SW: %s, data: %s' % (sw, data))

         envelope_sms_parser = argparse.ArgumentParser()
@@ -1556,7 +1556,7 @@
             dev_ids = DeviceIdentities(
                 decoded={'source_dev_id': 'network', 'dest_dev_id': 'uicc'})
             sms_dl = SMSPPDownload(children=[dev_ids, tpdu_ie])
-            (data, sw) = self._cmd.card._scc.envelope(b2h(sms_dl.to_tlv()))
+            (data, sw) = self._cmd.lchan.scc.envelope(b2h(sms_dl.to_tlv()))
             self._cmd.poutput('SW: %s, data: %s' % (sw, data))

         get_id_parser = argparse.ArgumentParser()
@@ -1570,7 +1570,7 @@
             context = 0x01 # SUCI
             if opts.nswo_context:
                 context = 0x02 # SUCI 5G NSWO
-            (data, sw) = self._cmd.card._scc.get_identity(context)
+            (data, sw) = self._cmd.lchan.scc.get_identity(context)
             do = SUCI_TlvDataObject()
             do.from_tlv(h2b(data))
             do_d = do.to_dict()
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 14db686..7413098 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -1001,7 +1001,7 @@
         @cmd2.with_argparser(authenticate_parser)
         def do_authenticate(self, opts):
             """Perform GSM Authentication."""
-            (data, sw) = self._cmd.card._scc.run_gsm(opts.rand)
+            (data, sw) = self._cmd.lchan.scc.run_gsm(opts.rand)
             self._cmd.poutput_json(data)



--
To view, visit https://gerrit.osmocom.org/c/pysim/+/34847?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: I13e2e871f2afc2460d9fd1cd566de42267c7d389
Gerrit-Change-Number: 34847
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <[email protected]>
Gerrit-MessageType: newchange

Reply via email to