smpp2sim: make the SCP81 BIP relay work

The BIP relay ( the "handset" side for SCP81) never worked: the
connect callback in handle_OpenChannel was "never called" as the fixme
says, everything else was missing.

Fixme cause: card APDU I/O is driven synchronously, proactive command loop
lives in a blocking while loop (pySim.transport.LinkBase.send_apdu_checksw)
that runs on the Twisted reactor thread. A Twisted TCP4ClientEndpoint +
connectProtocol only completes when the reactor does reactor things,
but the reactor thread is stuck in that loop for the whole proactive
session...

Fixme fix: don't fight the reactor, just drive the relay channel with a plain
old blocking socket, which fits the synchronous execution model.
Channel numbers now come from the command Device identities (channel_N ->
low nibble) instead of the hard coded chan_nr == 1.

Additionally fix two bugs found on the path to scp81 glory:
- TERMINAL RESPONSE device identities are forced to terminal->UICC per
  TS 102 223 6.8.2 (prepare_response() inverts the command identities,
  which for a channel-addressed BIP command yields channel_N->UICC).
- Error responses now build a valid AddlInfoBip cause, prepare_response()
  hard coded empty "additional information" cannot be encoded for a
  BIP error.

And some tests based on real card interactions.

Change-Id: If96c768f2e35c20ea3753e601059410121517b60
This commit is contained in:
Eric Wild
2026-09-23 17:51:04 +02:00
parent 5a54dd9eda
commit 6313b83e0e
3 changed files with 569 additions and 54 deletions
+26 -1
View File
@@ -30,6 +30,9 @@
import argparse
import logging
import socket
import threading
import time
import colorlog
from twisted.protocols import basic
@@ -55,6 +58,7 @@ from pySim.exceptions import *
from pySim.cat import ProactiveCommand, SendShortMessage, SMS_TPDU, SMSPPDownload, BearerDescription
from pySim.cat import DeviceIdentities, Address, OtherAddress, UiccTransportLevel, BufferSize
from pySim.cat import ChannelStatus, ChannelData, ChannelDataLength
from pySim.cat import EventList, EventDownload, Result
from pySim.utils import b2h, h2b
logger = logging.getLogger(__name__)
@@ -106,6 +110,11 @@ class MyServer:
smppEndpoint = endpoints.TCP6ServerEndpoint(reactor, tcp_port, interface=bind_ip)
smppEndpoint.listen(self.factory)
self.tp = self.scc = self.card = None
# Serialise card/APDU access.
# - SMPP handler drives the card from reactor thread
# - BIP relay data-available path drives it from socket reader thread.
# The transport is not re-entrant, both must take this lock.
self._card_lock = threading.Lock()
def connect_to_card(self, tp: LinkBase):
self.tp = tp
@@ -118,6 +127,21 @@ class MyServer:
self.card.select_adf_by_aid(adf='usim')
# FIXME: create a more realistic profile than ffffff
self.scc.terminal_profile('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
# Connect the BIP relay inbound path to the card.
# relay socket receives data -> ME initiated ENVELOPE EVENT DOWNLOA
# -> triggers RECEIVE DATA proactive session.
# FIXME this cross-thread push to the card is exercised only with real hardware
# the card free tests cover socket relay + envelope construction, not delivery.
handler = getattr(tp, 'proactive_handler', None)
if isinstance(handler, Proact):
handler.data_available_sink = self._deliver_data_available
def _deliver_data_available(self, envelope_hex: str):
"""push ME initiated ENVELOPE EVENT DOWNLOAD to the card"""
with self._card_lock:
logger.info("ENVELOPE(Data available): %s" % envelope_hex)
(data, sw) = self.scc.envelope(envelope_hex)
logger.info("SW %s: %s" % (sw, data))
def _msgHandler(self, system_id, smpp, pdu):
"""Handler for incoming messages received via SMPP from ESME."""
@@ -152,7 +176,8 @@ class MyServer:
# 3) send to the card
envelope_hex = b2h(sms_dl.to_tlv())
logger.info("ENVELOPE: %s" % envelope_hex)
(data, sw) = self.scc.envelope(envelope_hex)
with self._card_lock:
(data, sw) = self.scc.envelope(envelope_hex)
logger.info("SW %s: %s" % (sw, data))
if sw in ['9200', '9300']:
# TODO send back RP-ERROR message with TP-FCS == 'SIM Application Toolkit Busy'