fix: keep pySim's command-set bookkeeping in sync in the ES10 selections

After a profile switch the shell was unusable: every file select failed
with 'Attribute already exists: do_decode_hex (ShellCommands)' and even
equipping did not help - only a server restart recovered it.

pySim's equip() unregisters only the command sets of the file that is
selected at that moment, then re-registers everything while selecting
MF/EF.ICCID and MF with the app as cmd_app.  esim._select_isdr() selected
the ISD-R ADF without cmd_app, so MF's sets (ShellCommands, ...) stayed
registered while the selection moved to the ADF; the equip after the
profile switch then died re-registering them (cmd2 raises
CommandSetRegistrationError), leaving the app broken.

- _select_isdr() passes the shell app as cmd_app, so the old file's sets
  are unregistered and the ADF's (none) registered.
- _restore() passes it to soft_reset() too, so the MF re-selection updates
  the bookkeeping on both the success and the failure path.
- _esim_reinit() probes select('MF', app) after the equip and reports
  reinitialized: false on a registration error (a card-level select
  failure, e.g. no active profile, is tolerated).
- tests assert the cmd_app plumbing on the ISD-R select and the restore
  (profiles, chip and both switch paths).
This commit is contained in:
2026-09-22 00:46:14 +03:00
parent f6d62c225c
commit cb63ff286d
3 changed files with 44 additions and 10 deletions
+14
View File
@@ -19,6 +19,7 @@ from pysim_simple_server import netstate
from pysim_simple_server import scp81
from pysim_simple_server import esim
from smartcard.CardMonitoring import CardMonitor, CardObserver
from cmd2.exceptions import CommandSetRegistrationError
import gsm0338 # registers 'gsm03.38' codec
from construct import GreedyBytes
@@ -2594,6 +2595,19 @@ def _esim_reinit(server):
sys.stderr.write('ESIM: card gone during re-initialization\n')
return False
_apply_equipped_card(server)
# The equip must leave the shell's command-set registration consistent
# (pySim unregisters only the file selected at equip time). A broken
# registration only shows up on the next select made with the app, so
# probe it here: a card-level select failure (no active profile) is
# acceptable, a registration error is not.
try:
server.app.rs.lchan[0].select('MF', server.app)
except CommandSetRegistrationError as e:
sys.stderr.write('ESIM: shell command registration broken after '
're-initialization: %s\n' % e)
return False
except Exception as e:
sys.stderr.write('ESIM: post-equip MF select failed: %s\n' % e)
sys.stderr.write('ESIM: re-initialized after profile switch\n')
return True
except Exception as e: