Vadim Yanitskiy has uploaded this change for review. ( 
https://gerrit.osmocom.org/11480


Change subject: pySim/transport: introduce Calypso based reader interface
......................................................................

pySim/transport: introduce Calypso based reader interface

This interface allows to use a Calypso based phone (e.g. Motorola
C1XX) as a SIM card reader. It basically implements a few L1CTL
messages that are used to interact with the SIM card through
the OsmocomBB 'layer1' firmware.

Please note, that this is an experimental implementation, and
there is a risk that SIM programming would fail. Nevertheless,
I've managed to program and read one of my SIMs a few times.

Change-Id: Iec8101140581bf9e2cf7cf3a0b54bdf1875fc51b
---
M pySim/exceptions.py
A pySim/transport/calypso.py
2 files changed, 160 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/80/11480/1

diff --git a/pySim/exceptions.py b/pySim/exceptions.py
index 403f54c..831b1c9 100644
--- a/pySim/exceptions.py
+++ b/pySim/exceptions.py
@@ -31,3 +31,6 @@

 class ProtocolError(exceptions.Exception):
        pass
+
+class ReaderError(exceptions.Exception):
+       pass
diff --git a/pySim/transport/calypso.py b/pySim/transport/calypso.py
new file mode 100644
index 0000000..c0cfcbb
--- /dev/null
+++ b/pySim/transport/calypso.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+""" pySim: Transport Link for Calypso bases phones
+"""
+
+#
+# Copyright (C) 2018 Vadim Yanitskiy <axilira...@gmail.com>
+#
+# 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
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from __future__ import absolute_import
+
+import select
+import struct
+import socket
+import os
+
+from pySim.transport import LinkBase
+from pySim.exceptions import *
+from pySim.utils import h2b, b2h
+from pySim.utils import h2i, i2h
+
+class L1CTLMessage(object):
+
+       # Every (encoded) L1CTL message has the following structure:
+       #  - msg_length (2 bytes, net order)
+       #  - l1ctl_hdr (packed structure)
+       #    - msg_type
+       #    - flags
+       #    - padding (2 spare bytes)
+       #  - ... payload ...
+
+       def __init__(self, msg_type, flags = 0x00):
+               # Init L1CTL message header
+               self.data = struct.pack("BBxx", msg_type, flags)
+
+       def gen_msg(self):
+               return struct.pack("!H", len(self.data)) + self.data
+
+class L1CTLMessageReset(L1CTLMessage):
+
+       # L1CTL message types
+       L1CTL_RESET_REQ         = 0x0d
+       L1CTL_RESET_IND         = 0x07
+       L1CTL_RESET_CONF        = 0x0e
+
+       # Reset types
+       L1CTL_RES_T_BOOT        = 0x00
+       L1CTL_RES_T_FULL        = 0x01
+       L1CTL_RES_T_SCHED       = 0x02
+
+       def __init__(self, type = L1CTL_RES_T_FULL):
+               super(L1CTLMessageReset, self).__init__(self.L1CTL_RESET_REQ)
+               self.data += struct.pack("Bxxx", type)
+
+class L1CTLMessageSIM(L1CTLMessage):
+
+       # SIM related message types
+       L1CTL_SIM_REQ           = 0x16
+       L1CTL_SIM_CONF          = 0x17
+
+       def __init__(self, pdu):
+               super(L1CTLMessageSIM, self).__init__(self.L1CTL_SIM_REQ)
+               self.data += pdu
+
+class CalypsoSimLink(LinkBase):
+
+       def __init__(self, sock_path = "/tmp/osmocom_l2"):
+               # Make sure that a given socket path exists
+               if not os.path.exists(sock_path):
+                       raise ReaderError("There is no such ('%s') UNIX socket" 
% sock_path)
+
+               print("Connecting to osmocon at '%s'..." % sock_path)
+
+               # Establish a client connection
+               self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+               self.sock.connect(sock_path)
+
+       def __del__(self):
+               self.sock.close()
+
+       def reset_card(self):
+               # Request FULL reset
+               req_msg = L1CTLMessageReset()
+               self.sock.send(req_msg.gen_msg())
+
+               # Wait for confirmation (timeout is 3 seconds)
+               s, _, _ = select.select([self.sock], [], [], 3.0)
+               if not s:
+                       raise ReaderError("Timeout waiting for L1CTL_RESET_REQ")
+               else:
+                       rsp = self.sock.recv(128)
+                       rsp_msg = struct.unpack_from("!HB", rsp)
+                       if rsp_msg[1] != L1CTLMessageReset.L1CTL_RESET_CONF:
+                               raise ReaderError("Failed to reset Calypso PHY")
+
+       def connect(self):
+               self.reset_card()
+
+       def disconnect(self):
+               pass # Nothing to do really ...
+
+       def wait_for_card(self, timeout = None, newcardonly = False):
+               pass # Nothing to do really ...
+
+       def send_apdu_raw(self, pdu):
+               """see LinkBase.send_apdu_raw"""
+
+               # Request FULL reset
+               req_msg = L1CTLMessageSIM(h2b(pdu))
+               self.sock.send(req_msg.gen_msg())
+
+               # Wait for confirmation (timeout is 3 seconds)
+               s, _, _ = select.select([self.sock], [], [], 3.0)
+               if not s:
+                       raise ReaderError("Timeout waiting for L1CTL_SIM_CONF")
+
+               # Read message length first
+               rsp = self.sock.recv(struct.calcsize("!H"))
+               msg_len = struct.unpack_from("!H", rsp)[0]
+               if msg_len < struct.calcsize("BBxx"):
+                       raise ReaderError("Missing L1CTL header for 
L1CTL_SIM_CONF")
+
+               # Read the whole message then
+               rsp = self.sock.recv(msg_len)
+
+               # Verify L1CTL header
+               hdr = struct.unpack_from("BBxx", rsp)
+               if hdr[0] != L1CTLMessageSIM.L1CTL_SIM_CONF:
+                       raise ReaderError("Failed to reset Calypso PHY")
+
+               # Verify the payload length
+               offset = struct.calcsize("BBxx")
+               if len(rsp) <= offset:
+                       raise ProtocolError("Empty response from SIM?!?")
+
+               # Omit L1CTL header
+               rsp = rsp[offset:]
+
+               # Unpack data and SW
+               data = rsp[:-2]
+               sw = rsp[-2:]
+
+               return b2h(data), b2h(sw)

--
To view, visit https://gerrit.osmocom.org/11480
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iec8101140581bf9e2cf7cf3a0b54bdf1875fc51b
Gerrit-Change-Number: 11480
Gerrit-PatchSet: 1
Gerrit-Owner: Vadim Yanitskiy <axilira...@gmail.com>

Reply via email to