summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/l1ctl_proto.h4
-rw-r--r--src/host/layer23/configure.ac9
-rw-r--r--src/host/layer23/include/osmocom/bb/common/l1ctl.h3
-rw-r--r--src/host/layer23/src/Makefile.am2
-rw-r--r--src/host/layer23/src/common/l1ctl.c57
-rw-r--r--src/host/layer23/src/libosmosim/Makefile.am7
-rw-r--r--src/host/layer23/src/libosmosim/libosmosim.c296
-rw-r--r--src/host/layer23/src/libosmosim/libosmosim.h9
-rw-r--r--src/target/firmware/apps/layer1/main.c4
-rw-r--r--src/target/firmware/calypso/sim.c334
-rw-r--r--src/target/firmware/layer1/l23_api.c61
11 files changed, 622 insertions, 164 deletions
diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h
index 771bf1c3..beceddf5 100644
--- a/include/l1ctl_proto.h
+++ b/include/l1ctl_proto.h
@@ -49,6 +49,10 @@ enum {
L1CTL_CRYPTO_REQ,
L1CTL_SIM_REQ,
L1CTL_SIM_CONF,
+ L1CTL_SIM_POWERUP,
+ L1CTL_SIM_POWERDOWN,
+ L1CTL_SIM_RESET,
+ L1CTL_SIM_ATR,
L1CTL_TCH_MODE_REQ,
L1CTL_TCH_MODE_CONF,
L1CTL_NEIGH_PM_REQ,
diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac
index 9335e66e..94fd79b0 100644
--- a/src/host/layer23/configure.ac
+++ b/src/host/layer23/configure.ac
@@ -10,7 +10,9 @@ dnl checks for programs
AC_PROG_MAKE_SET
AC_PROG_CC
AC_PROG_INSTALL
-AC_PROG_RANLIB
+dnl AC_PROG_RANLIB
+LT_INIT
+AC_PROG_LIBTOOL
dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore)
@@ -30,8 +32,9 @@ dnl Checks for typedefs, structures and compiler characteristics
AC_OUTPUT(
src/Makefile
src/common/Makefile
- src/misc/Makefile
- src/mobile/Makefile
+ dnl src/misc/Makefile
+ dnl src/mobile/Makefile
+ src/libosmosim/Makefile
include/Makefile
include/osmocom/Makefile
include/osmocom/bb/Makefile
diff --git a/src/host/layer23/include/osmocom/bb/common/l1ctl.h b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
index 3534589d..1f56d7c7 100644
--- a/src/host/layer23/include/osmocom/bb/common/l1ctl.h
+++ b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
@@ -62,6 +62,9 @@ int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
uint16_t arfcn_to);
int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length);
+int l1ctl_tx_sim_powerup(struct osmocom_ms *ms);
+int l1ctl_tx_sim_powerdown(struct osmocom_ms *ms);
+int l1ctl_tx_sim_reset(struct osmocom_ms *ms);
/* Transmit L1CTL_VOICE_REQ */
int l1ctl_tx_traffic_req(struct osmocom_ms *ms, struct msgb *msg,
diff --git a/src/host/layer23/src/Makefile.am b/src/host/layer23/src/Makefile.am
index 58a5f7fb..a9174f18 100644
--- a/src/host/layer23/src/Makefile.am
+++ b/src/host/layer23/src/Makefile.am
@@ -1 +1 @@
-SUBDIRS = common misc mobile
+SUBDIRS = common libosmosim
diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c
index 91bab897..f1bb2823 100644
--- a/src/host/layer23/src/common/l1ctl.c
+++ b/src/host/layer23/src/common/l1ctl.c
@@ -49,6 +49,8 @@
#include <osmocom/bb/common/logging.h>
#include <osmocom/codec/codec.h>
+extern void osmosim_sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg);
+extern void osmosim_sim_up_resp(struct osmocom_ms *ms, struct msgb *msg);
extern struct gsmtap_inst *gsmtap_inst;
static int apdu_len = -1;
@@ -650,6 +652,39 @@ int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
return osmo_send_l1(ms, msg);
}
+int l1ctl_tx_sim_powerup(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+
+ msg = osmo_l1_alloc(L1CTL_SIM_POWERUP);
+ if (!msg)
+ return -1;
+
+ return osmo_send_l1(ms, msg);
+}
+
+int l1ctl_tx_sim_powerdown(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+
+ msg = osmo_l1_alloc(L1CTL_SIM_POWERDOWN);
+ if (!msg)
+ return -1;
+
+ return osmo_send_l1(ms, msg);
+}
+
+int l1ctl_tx_sim_reset(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+
+ msg = osmo_l1_alloc(L1CTL_SIM_RESET);
+ if (!msg)
+ return -1;
+
+ return osmo_send_l1(ms, msg);
+}
+
/* just forward the SIM response to the SIM handler */
static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -669,11 +704,28 @@ static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
msgb_pull(msg, sizeof(struct l1ctl_hdr));
msg->l1h = NULL;
- sim_apdu_resp(ms, msg);
+ osmosim_sim_apdu_resp(ms, msg);
return 0;
}
+static int rx_l1_sim_atr(struct osmocom_ms *ms, struct msgb *msg)
+{
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+
+ LOGP(DL1C, LOGL_INFO, "SIM ATR (len=%d) : %s\n", len, osmo_hexdump(data, len));
+
+ /* pull the L1 header from the msgb */
+ msgb_pull(msg, sizeof(struct l1ctl_hdr));
+ msg->l1h = NULL;
+
+ osmosim_sim_up_resp(ms, msg);
+
+ msgb_free(msg);
+ return 0;
+}
+
/* Transmit L1CTL_PM_REQ */
int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
uint16_t arfcn_to)
@@ -972,6 +1024,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
case L1CTL_SIM_CONF:
rc = rx_l1_sim_conf(ms, msg);
break;
+ case L1CTL_SIM_ATR:
+ rc = rx_l1_sim_atr(ms, msg);
+ break;
case L1CTL_NEIGH_PM_IND:
rc = rx_l1_neigh_pm_ind(ms, msg);
msgb_free(msg);
diff --git a/src/host/layer23/src/libosmosim/Makefile.am b/src/host/layer23/src/libosmosim/Makefile.am
new file mode 100644
index 00000000..bcc263a0
--- /dev/null
+++ b/src/host/layer23/src/libosmosim/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I/home/gsmmap/jdk1.7.0_45/include -I/home/gsmmap/jdk1.7.0_45/include/linux
+AM_CFLAGS = -Wall -g $(LIBOSMOCORE_CFLAGS)
+LDADD = $(LIBOSMOCORE_LIBS)
+
+lib_LTLIBRARIES = libosmosim.la
+libosmosim_la_SOURCES = ../common/l1ctl.c ../common/logging.c ../common/l1l2_interface.c libosmosim.c
+libosmosim_la_LIBADD = $(LDADD)
diff --git a/src/host/layer23/src/libosmosim/libosmosim.c b/src/host/layer23/src/libosmosim/libosmosim.c
new file mode 100644
index 00000000..e6f91646
--- /dev/null
+++ b/src/host/layer23/src/libosmosim/libosmosim.c
@@ -0,0 +1,296 @@
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/l1l2_interface.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/core/talloc.h>
+#include <l1ctl_proto.h>
+
+#define LIBOSMOSIM_DEBUG 0
+
+#define libosmosim_dbg(fmt, ...) \
+ do { if (LIBOSMOSIM_DEBUG) fprintf(stderr, fmt, __VA_ARGS__); } while (0)
+
+#define _GNU_SOURCE
+#include <unistd.h>
+
+#include "libosmosim.h"
+
+// layer 2 connection variables
+static char *layer2_socket_path = "/tmp/osmocom_l2";
+static void *l23_ctx = NULL;
+static struct osmocom_ms *ms = NULL;
+
+// locking variables
+struct log_target *stderr_target;
+static char lckfile[] = "/tmp/.osmosim_lock";
+static FILE *flckfile;
+
+// fake stuff that is needed in l1ctl.c and is never used in our code
+struct gsmtap_inst *gsmtap_inst = NULL;
+const uint16_t gsm610_bitorder[] = {};
+
+// sim present in phone identifier
+static int sim_present = 0;
+
+// global APDU buffer
+static uint8_t apdu_resp[255];
+static size_t apdu_length = 0;
+
+/*
+ * helper locking functions to ensure only 1 operations is performed by a Osmocom BB phone at the same time
+ */
+
+static int in_shutdown = 0;
+int i = 0;
+void unlock() {
+ int j = i++;
+ libosmosim_dbg("unlock() called, tring to unlock %d\n", j);
+ funlockfile(flckfile);
+ libosmosim_dbg("unlocked %d, unlock() exiting\n", j);
+}
+
+void dolock() {
+ int j = i++;
+ libosmosim_dbg("dolock() called, tring to lock %d\n", j);
+ flockfile(flckfile);
+ libosmosim_dbg("locked %d, dolock() exiting\n", j);
+}
+
+void lock() {
+ libosmosim_dbg("%s\n", "lock() called");
+ if (in_shutdown) {
+ libosmosim_dbg("%s\n", "lock() waiting as in_shutdown is 1");
+ sleep(1337); // just wait forever as we're shutdowning already, no action is allowed.
+ }
+ dolock();
+ libosmosim_dbg("%s\n", "lock() exiting");
+}
+
+/*
+ * callback functions
+ */
+
+/* this function is called-back when L1CTL_SIM_ATR message is received (when SIM needs to return ATR) */
+int osmosim_sim_up_resp(struct osmocom_ms *ms, struct msgb *msg) {
+ libosmosim_dbg("%s\n", "sim_up_resp() called");
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ if (len > 0) {
+ sim_present = 1;
+ }
+
+ uint8_t *data = msg->data;
+ int length = msg->len;
+ LOGP(DSIM, LOGL_INFO, "SIM ATR (len=%d) : %s\n", length, osmo_hexdump(data, length));
+ apdu_length = length;
+ memcpy(apdu_resp, data, length);
+ unlock(); // unlock a lock performed by osmo_sim_powerup() and osmosim_reset()
+ libosmosim_dbg("%s\n", "sim_up_resp() exiting");
+ return len;
+}
+
+/* this function is called-back when L1CTL_SIM_CONF message is received (when SIM needs to return a response to APDU) */
+int osmosim_sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg) {
+ libosmosim_dbg("%s\n", "sim_apdu_resp() called");
+ uint8_t *data = msg->data;
+ int length = msg->len;
+ uint8_t sw1, sw2;
+ /* process status */
+ if (length < 2) {
+ msgb_free(msg);
+ return 0;
+ }
+ sw1 = data[length - 2];
+ sw2 = data[length - 1];
+ LOGP(DSIM, LOGL_INFO, "received APDU (len=%d sw1=0x%02x sw2=0x%02x)\n", length, sw1, sw2);
+
+ apdu_length = length;
+ memcpy(apdu_resp, data, length);
+
+ unlock();
+ libosmosim_dbg("%s\n", "sim_apdu_resp() exiting");
+ return 0;
+}
+
+/*
+ * osmosim_* functions that communicate over layer 1
+ */
+
+/* initialize stderr_target and set default logging to all known debug symbols + LOGL_FATAL */
+void osmosim_log_init() {
+ libosmosim_dbg("%s\n", "osmosim_log_init() called");
+ log_init(&log_info, NULL);
+ stderr_target = NULL;
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
+ const char *debug_default = "DCS:DNB:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DSS:DLSMS:DPAG:DSUM:DL1C";
+ log_parse_category_mask(stderr_target, debug_default);
+ log_set_log_level(stderr_target, LOGL_FATAL);
+ libosmosim_dbg("%s\n", "osmosim_log_init() exiting");
+}
+
+/* open layer2 socket and prepare ms struct for communication with Osmocom BB phone */
+int osmosim_init()
+{
+ libosmosim_dbg("%s\n", "osmosim_init() called");
+ int rc;
+
+ flckfile = fopen(lckfile, "w"); // open a lock file
+ if (!stderr_target) {
+ osmosim_log_init();
+ }
+
+ l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
+
+ ms = talloc_zero(l23_ctx, struct osmocom_ms);
+ if (!ms) {
+ fprintf(stderr, "Failed to allocate MS\n");
+ return 0;
+ }
+
+ sprintf(ms->name, "1");
+
+ rc = layer2_open(ms, layer2_socket_path);
+ if (rc < 0) {
+ fprintf(stderr, "Failed during layer2_open()\n");
+ return 0;
+ }
+
+ libosmosim_dbg("%s\n", "osmosim_init() exiting");
+ return 1;
+}
+
+/* sets a loglevel if log_level != 0 as zero means "don't set loglevel only return the current one" */
+int osmosim_loglevel(int log_level) {
+ libosmosim_dbg("%s%s%s\n", "osmosim_log_level() called (log_level = ", log_level_str(log_level), ")");
+ if (!stderr_target) {
+
+ osmosim_log_init();
+ }
+
+ if (log_level) {
+ log_set_log_level(stderr_target, log_level);
+ }
+
+ libosmosim_dbg("%s\n", "osmosim_log_level() exiting");
+ return stderr_target->loglevel;
+}
+
+/* power up the sim (actual voltage) */
+int osmosim_powerup() {
+ libosmosim_dbg("%s\n", "osmosim_powerup() called");
+ in_shutdown = 0;
+ lock();
+ l1ctl_tx_sim_powerup(ms);
+ osmo_select_main(0); // wait for write to the socket
+ osmo_select_main(0); // wait for read from the socket
+
+ libosmosim_dbg("%s\n", "osmosim_powerup() exiting");
+ return sim_present; // 1 if sim is in the phone, 0 if sim is absent
+}
+
+/* power down the sim (actual voltage) */
+void osmosim_powerdown() {
+ libosmosim_dbg("%s\n", "osmosim_powerdown() called");
+ in_shutdown = 1;
+ dolock();
+ l1ctl_tx_sim_powerdown(ms);
+ osmo_select_main(0); // wait for write to the socket (no response required)
+ unlock();
+ libosmosim_dbg("%s\n", "osmosim_powerdown() exiting");
+}
+
+/* trigger SIM reset (actuall reset pin on the sim) */
+int osmosim_reset() {
+ libosmosim_dbg("%s\n", "osmosim_reset() called");
+ lock();
+ l1ctl_tx_sim_reset(ms);
+ osmo_select_main(0); // wait for write to the socket
+ osmo_select_main(0); // wait for read from the socket
+
+ libosmosim_dbg("%s\n", "osmosim_reset() exiting");
+ return sim_present;
+}
+
+/* transmit a APDU to the SIM and wait for response to arrive (sim_apdu_resp), then read it out of a global buffer) */
+int osmosim_transmit(char* data, unsigned int len, char** out)
+{
+ libosmosim_dbg("%s\n", "osmosim_transmit() called");
+ lock();
+ LOGP(DSIM, LOGL_INFO, "sending APDU (class 0x%02x, ins 0x%02x)\n", data[0], data[1]);
+ l1ctl_tx_sim_req(ms, (uint8_t*)data, len);
+ osmo_select_main(0);
+ osmo_select_main(0);
+
+ if (out) {
+ *out = (char*)&apdu_resp;
+ }
+ libosmosim_dbg("%s\n", "osmosim_transmit() exiting");
+ return apdu_length;
+}
+
+/* perform lock without checking for shutdown as this is initiated during shutdown */
+void osmosim_exit() {
+ libosmosim_dbg("%s\n", "osmosim_exit() called");
+ dolock();
+ layer2_close(ms);
+ talloc_free(ms);
+ talloc_free(l23_ctx);
+ log_target_destroy(stderr_target);
+ stderr_target = NULL;
+ unlock();
+ fclose(flckfile);
+ libosmosim_dbg("%s\n", "osmosim_exit() exiting");
+}
+
+/*
+ * Java highlevel API wrappers for functions above
+ */
+
+JNIEXPORT jboolean JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_init (JNIEnv *env, jobject obj) {
+ return osmosim_init();
+}
+
+JNIEXPORT jint JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_loglevel (JNIEnv *env, jobject obj, jint log_level) {
+ return osmosim_loglevel(log_level);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_simPowerup (JNIEnv *env, jobject obj) {
+
+ osmosim_powerup();
+
+ jbyteArray result;
+ result = (*env)->NewByteArray(env, apdu_length);
+ (*env)->SetByteArrayRegion(env, result, 0, apdu_length, (jbyte*)apdu_resp);
+
+ return result;
+}
+
+JNIEXPORT void JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_simPowerdown (JNIEnv *env, jobject obj) {
+ osmosim_powerdown();
+}
+
+JNIEXPORT jboolean JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_simReset (JNIEnv *env, jobject obj) {
+ return osmosim_reset();
+}
+
+JNIEXPORT jbyteArray JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_transmit (JNIEnv *env, jobject obj, jbyteArray data) {
+
+ char req[255];
+ int len;
+ char *resp;
+
+ len = (*env)->GetArrayLength(env, data);
+ (*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)req);
+
+ len = osmosim_transmit(req, len, &resp);
+
+ jbyteArray result;
+ result = (*env)->NewByteArray(env, len);
+ (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resp);
+
+ return result;
+}
+
+JNIEXPORT void JNICALL Java_de_srlabs_simlib_osmocardprovider_OsmoJNI_exit (JNIEnv *env, jobject obj) {
+ osmosim_exit();
+}
diff --git a/src/host/layer23/src/libosmosim/libosmosim.h b/src/host/layer23/src/libosmosim/libosmosim.h
new file mode 100644
index 00000000..444e9f05
--- /dev/null
+++ b/src/host/layer23/src/libosmosim/libosmosim.h
@@ -0,0 +1,9 @@
+#include <jni.h>
+
+int osmosim_init();
+int osmosim_loglevel(int log_level);
+int osmosim_powerup();
+void osmosim_powerdown();
+int osmosim_reset();
+int osmosim_transmit(char* data, unsigned int len, char** out);
+void osmosim_exit();
diff --git a/src/target/firmware/apps/layer1/main.c b/src/target/firmware/apps/layer1/main.c
index 59ffe972..ab31b92c 100644
--- a/src/target/firmware/apps/layer1/main.c
+++ b/src/target/firmware/apps/layer1/main.c
@@ -102,9 +102,11 @@ int main(void)
/* initialize SIM */
calypso_sim_init();
+#if 0
puts("Power up simcard:\n");
memset(atr,0,sizeof(atr));
atrLength = calypso_sim_powerup(atr);
+#endif
layer1_init();
@@ -167,7 +169,7 @@ static void key_handler(enum key_codes code, enum key_states state)
}
/* power down SIM, TODO: this will happen with every key pressed,
put it somewhere else ! */
- calypso_sim_powerdown();
+ //calypso_sim_powerdown();
}
diff --git a/src/target/firmware/calypso/sim.c b/src/target/firmware/calypso/sim.c
index 752628fd..19501daa 100644
--- a/src/target/firmware/calypso/sim.c
+++ b/src/target/firmware/calypso/sim.c
@@ -43,6 +43,7 @@
/* Class that contains the following instructions */
#define SIM_GET_RESPONSE 0xC0
/* Get the response of a command from the card */
+#define SIM_FETCH 0x12
#define SIM_READ_BINARY 0xB0 /* Read file in binary mode */
#define SIM_READ_RECORD 0xB2 /* Read record in binary mode */
@@ -347,7 +348,7 @@ void calypso_sim_regdump(void)
/* Receive raw data through the sim interface */
int calypso_sim_receive(uint8_t *data, uint8_t len)
{
- printd("Triggering SIM reception\n");
+ printd("Triggering SIM reception, len = %d bytes\n", len);
/* Prepare buffers and flags */
rx_buffer = data;
@@ -396,12 +397,12 @@ void sim_irq_handler(enum irq_nr irq)
{
int regVal = readw(REG_SIM_IT);
-
/* Display interrupt information */
printd("SIM-ISR: ");
if(regVal & REG_SIM_IT_SIM_NATR) {
- printd(" No answer to reset!\n");
+ puts("SIM: No answer to reset!\n");
+ rxDoneFlag = 1;
}
/* Used by: calypso_sim_receive() to determine when the transmission
@@ -410,7 +411,6 @@ void sim_irq_handler(enum irq_nr irq)
if(regVal & REG_SIM_IT_SIM_WT) {
printd(" Character underflow!\n");
rxDoneFlag = 1;
-
}
if(regVal & REG_SIM_IT_SIM_OV) {
@@ -444,31 +444,36 @@ void sim_irq_handler(enum irq_nr irq)
/* Used by: calypso_sim_receive() to receive the incoming data */
if(regVal & REG_SIM_IT_SIM_RX) {
- uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
-
- /* ignore NULL procedure byte */
- if(ch == 0x60 && sim_ignore_waiting_char) {
- printd(" 0x60 received...\n");
- return;
- }
-
- printd(" Waiting for read (%02X)...\n", ch);
-
- /* Increment character count - this is what
- * calypso_sim_receive() hands back
- */
- sim_rx_character_count++;
+ /* read while FIFO is not empty
+ otherwise we can get FIFO full if we wait for REG_SIM_IT_SIM_RX for each char */
+ while ((readw(REG_SIM_STAT) & REG_SIM_STAT_STATFIFOEMPTY) == 0) {
+ uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
+
+ /* ignore NULL procedure byte */
+ if(ch == 0x60 && sim_ignore_waiting_char) {
+ printd(" 0x60 received...\n");
+ return;
+ }
- /* Read byte from rx-fifo and write it to the issued buffer */
- *rx_buffer = ch;
- rx_buffer++;
+ printd(" Waiting for read (%02X)...\n", ch);
- /* to maximise SIM access speed, stop waiting after
- all the expected characters have been received. */
- if (sim_rx_max_character_count
- && sim_rx_character_count >= sim_rx_max_character_count) {
- printd(" Max characters received!\n");
- rxDoneFlag = 1;
+ /* Increment character count - this is what
+ * calypso_sim_receive() hands back
+ */
+ sim_rx_character_count++;
+
+ /* Read byte from rx-fifo and write it to the issued buffer */
+ *rx_buffer = ch;
+ rx_buffer++;
+
+ /* to maximise SIM access speed, stop waiting after
+ all the expected characters have been received. */
+ if (sim_rx_max_character_count
+ && sim_rx_character_count >= sim_rx_max_character_count) {
+ printd(" Max characters received!\n");
+ rxDoneFlag = 1;
+ break;
+ }
}
}
}
@@ -477,7 +482,7 @@ void sim_irq_handler(enum irq_nr irq)
void sim_apdu(uint16_t len, uint8_t *data)
{
if (sim_state != SIM_STATE_IDLE) {
- puts("Sim reader currently busy...\n");
+ puts("SIM: reader currently busy...\n");
return;
}
memcpy(sim_data, data, len);
@@ -494,139 +499,141 @@ void sim_handler(void)
static uint16_t length;
switch (sim_state) {
- case SIM_STATE_IDLE:
- if (!sim_len)
- break; /* wait for SIM command */
- /* check if instructions expects a response */
- if (/* GET RESPONSE needs SIM_APDU_GET */
- (sim_len == 5 && sim_data[0] == SIM_CLASS &&
- sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 &&
- sim_data[3] == 0x00) ||
- /* READ BINARY/RECORD needs SIM_APDU_GET */
- (sim_len >= 5 && sim_data[0] == SIM_CLASS &&
- (sim_data[1] == SIM_READ_BINARY ||
- sim_data[1] == SIM_READ_RECORD)))
- mode = SIM_APDU_GET;
- else
- mode = SIM_APDU_PUT;
-
- length = sim_data[4];
-
- /* allocate space for expected response */
- msg = msgb_alloc_headroom(256, L3_MSG_HEAD
+ case SIM_STATE_IDLE:
+ if (!sim_len)
+ break; /* wait for SIM command */
+ /* check if instructions expects a response */
+ if (/* GET RESPONSE needs SIM_APDU_GET */
+ (sim_len == 5 && sim_data[0] == SIM_CLASS &&
+ (sim_data[1] == SIM_GET_RESPONSE || sim_data[1] == SIM_FETCH) && sim_data[2] == 0x00 &&
+ sim_data[3] == 0x00) ||
+ /* READ BINARY/RECORD needs SIM_APDU_GET */
+ (sim_len >= 5 && sim_data[0] == SIM_CLASS &&
+ (sim_data[1] == SIM_READ_BINARY ||
+ sim_data[1] == SIM_READ_RECORD)))
+ mode = SIM_APDU_GET;
+ else
+ mode = SIM_APDU_PUT;
+
+ length = sim_data[4];
+
+ /* allocate space for expected response */
+ msg = msgb_alloc_headroom(256, L3_MSG_HEAD
+ sizeof(struct l1ctl_hdr), "l1ctl1");
- response = msgb_put(msg, length + 2 + 1);
-
- sim_state = SIM_STATE_TX_HEADER;
-
- /* send APDU header */
- calypso_sim_transmit(sim_data, 5);
- break;
- case SIM_STATE_TX_HEADER:
- if (!txDoneFlag)
- break; /* wait until header is transmitted */
- /* Disable all interrupt driven functions */
- writew(0xFF, REG_SIM_MASKIT);
- /* Case 1: No input, No Output */
- if (length == 0) {
- sim_state = SIM_STATE_RX_STATUS;
- calypso_sim_receive(response + 1, 2);
+ response = msgb_put(msg, length + 2 + 1);
+
+ sim_state = SIM_STATE_TX_HEADER;
+
+ /* send APDU header */
+ calypso_sim_transmit(sim_data, 5);
break;
- }
- /* Case 2: No input / Output of known length */
- if (mode == SIM_APDU_PUT) {
- sim_state = SIM_STATE_RX_ACK;
- calypso_sim_receive(response, 1);
+ case SIM_STATE_TX_HEADER:
+ if (!txDoneFlag)
+ break; /* wait until header is transmitted */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* Case 1: No input, No Output */
+ if (length == 0) {
+ sim_state = SIM_STATE_RX_STATUS;
+ calypso_sim_receive(response + 1, 2);
+ break;
+ }
+ /* Case 2: No input / Output of known length */
+ if (mode == SIM_APDU_PUT) {
+ sim_state = SIM_STATE_RX_ACK;
+ calypso_sim_receive(response, 1);
+ break;
+ /* Case 4: Input / No output */
+ } else {
+ sim_state = SIM_STATE_RX_ACK_DATA;
+ calypso_sim_receive(response, length + 1 + 2);
+ }
break;
- /* Case 4: Input / No output */
- } else {
- sim_state = SIM_STATE_RX_ACK_DATA;
- calypso_sim_receive(response, length + 1 + 2);
- }
- break;
- case SIM_STATE_RX_STATUS:
- if (!rxDoneFlag)
- break; /* wait until data is received */
- /* Disable all interrupt driven functions */
- writew(0xFF, REG_SIM_MASKIT);
- /* disable special ignore case */
- sim_ignore_waiting_char = 0;
- /* wrong number of bytes received */
- if (sim_rx_character_count != 2) {
- puts("SIM: Failed to read status\n");
- goto error;
- }
- msgb_pull(msg, length + 1); /* pull up to status info */
- goto queue;
- case SIM_STATE_RX_ACK:
- if (!rxDoneFlag)
- break; /* wait until data is received */
- /* Disable all interrupt driven functions */
- writew(0xFF, REG_SIM_MASKIT);
- /* error received */
- if (sim_rx_character_count == 2) {
- puts("SIM: command failed\n");
- msgb_pull(msg, msg->len - 2);
- msg->data[0] = response[0];
- msg->data[1] = response[1];
+ case SIM_STATE_RX_STATUS:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* disable special ignore case */
+ sim_ignore_waiting_char = 0;
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != 2) {
+ puts("SIM: Failed to read status\n");
+ goto error;
+ }
+ msgb_pull(msg, length + 1); /* pull up to status info */
goto queue;
- }
- /* wrong number of bytes received */
- if (sim_rx_character_count != 1) {
- puts("SIM: ACK read failed\n");
- goto error;
- }
- if (response[0] != sim_data[1]) {
- puts("SIM: ACK does not match request\n");
- goto error;
- }
- sim_state = SIM_STATE_TX_DATA;
- calypso_sim_transmit(sim_data + 5, length);
- break;
- case SIM_STATE_TX_DATA:
- if (!txDoneFlag)
- break; /* wait until data is transmitted */
- /* Disable all interrupt driven functions */
- writew(0xFF, REG_SIM_MASKIT);
- /* Ignore waiting char for RUN GSM ALGORITHM */
- /* TODO: implement proper handling of the "Procedure Bytes"
- than this is no longer needed */
- if(sim_data[1] == 0x88)
- sim_ignore_waiting_char = 1;
- sim_state = SIM_STATE_RX_STATUS;
- calypso_sim_receive(response + length + 1, 2);
- break;
- case SIM_STATE_RX_ACK_DATA:
- if (!rxDoneFlag)
- break; /* wait until data is received */
- /* Disable all interrupt driven functions */
- writew(0xFF, REG_SIM_MASKIT);
- /* error received */
- if (sim_rx_character_count == 2) {
- puts("SIM: command failed\n");
- msgb_pull(msg, msg->len - 2);
- msg->data[0] = response[0];
- msg->data[1] = response[1];
+ case SIM_STATE_RX_ACK:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* error received */
+ if (sim_rx_character_count == 2) {
+ puts("SIM: command failed\n");
+ msgb_pull(msg, msg->len - 2);
+ msg->data[0] = response[0];
+ msg->data[1] = response[1];
+ goto queue;
+ }
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != 1) {
+ puts("SIM: ACK read failed\n");
+ goto error;
+ }
+ if (response[0] != sim_data[1]) {
+ puts("SIM: ACK does not match request\n");
+ goto error;
+ }
+ sim_state = SIM_STATE_TX_DATA;
+ calypso_sim_transmit(sim_data + 5, length);
+ break;
+ case SIM_STATE_TX_DATA:
+ if (!txDoneFlag)
+ break; /* wait until data is transmitted */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* Ignore waiting char for RUN GSM ALGORITHM */
+ /* TODO: implement proper handling of the "Procedure Bytes"
+ than this is no longer needed */
+ if(sim_data[1] == 0x88)
+ sim_ignore_waiting_char = 1;
+ sim_state = SIM_STATE_RX_STATUS;
+ calypso_sim_receive(response + length + 1, 2);
+ break;
+ case SIM_STATE_RX_ACK_DATA:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* error received */
+ if (sim_rx_character_count == 2) {
+ puts("SIM: command failed\n");
+ msgb_pull(msg, msg->len - 2);
+ msg->data[0] = response[0];
+ msg->data[1] = response[1];
+ goto queue;
+ }
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != length + 1 + 2) {
+ puts("SIM: Failed to read data\n");
+ goto error;
+ }
+ msgb_pull(msg, 1); /* pull ACK byte */
goto queue;
- }
- /* wrong number of bytes received */
- if (sim_rx_character_count != length + 1 + 2) {
- puts("SIM: Failed to read data\n");
- goto error;
- }
- msgb_pull(msg, 1); /* pull ACK byte */
- goto queue;
}
return;
error:
msgb_pull(msg, msg->len - 2);
- msg->data[0] = 0;
- msg->data[1] = 0;
+ msg->data[0] = 0xba;
+ msg->data[1] = 0xad;
queue:
+#ifdef DEBUG /* for debugging only */
printf("SIM Response (%d): %s\n", msg->len,
- osmo_hexdump(msg->data, msg->len));
+ osmo_hexdump(msg->data, msg->len));
+#endif
l1h = (struct l1ctl_hdr *) msgb_push(msg, sizeof(*l1h));
l1h->msg_type = L1CTL_SIM_CONF;
l1h->flags = 0;
@@ -659,10 +666,14 @@ void calypso_sim_init(void)
/* Apply power to the simcard (use nullpointer to ignore atr) */
int calypso_sim_powerup(uint8_t *atr)
{
+ /* put state machine back into idle */
+ sim_len = 0;
+ sim_state = SIM_STATE_IDLE;
+
/* Enable level shifters and voltage regulator */
#if 1 // 2.9V
twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN
- | VRPCSIM_SIMSEL);
+ | VRPCSIM_SIMSEL);
#else // 1.8V
twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN);
#endif
@@ -676,8 +687,8 @@ int calypso_sim_powerup(uint8_t *atr)
/* Release reset */
writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFBYPASS
- | REG_SIM_CONF1_CONFSRSTLEV
- | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1);
+ | REG_SIM_CONF1_CONFSRSTLEV
+ | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1);
printd(" * Reset released!\n");
/* Catch ATR */
@@ -687,14 +698,19 @@ int calypso_sim_powerup(uint8_t *atr)
;
}
- return 0;
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+
+ return sim_rx_character_count;
}
/* Powerdown simcard */
void calypso_sim_powerdown(void)
{
- writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFBYPASS, REG_SIM_CONF1);
+ // according to the specification CONFTXRX | CONFSCLKEN is a default reset value of conf1 register
+ // if CONFSVCCLEV or CONFSRSTLEV remains enabled even without CONFBYPASS, SIM is never properly powered down
+ writew(REG_SIM_CONF1_CONFTXRX | REG_SIM_CONF1_CONFSCLKEN, REG_SIM_CONF1);
printd(" * Reset pulled down!\n");
delay_ms(SIM_OPERATION_DELAY);
@@ -710,14 +726,13 @@ void calypso_sim_powerdown(void)
twl3025_reg_write(VRPCSIM, 0);
printd(" * Power disabled!\n");
delay_ms(SIM_OPERATION_DELAY);
-
+
return;
}
/* reset the simcard (see note 1) */
int calypso_sim_reset(uint8_t *atr)
{
-
/* Pull reset down */
writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFSRSTLEV,
REG_SIM_CONF1);
@@ -725,6 +740,10 @@ int calypso_sim_reset(uint8_t *atr)
delay_ms(SIM_OPERATION_DELAY);
+ /* put state machine back into idle */
+ sim_len = 0;
+ sim_state = SIM_STATE_IDLE;
+
/* Pull reset down */
writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV, REG_SIM_CONF1);
printd(" * Reset released!\n");
@@ -736,6 +755,9 @@ int calypso_sim_reset(uint8_t *atr)
;
}
- return 0;
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+
+ return sim_rx_character_count;
}
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index ae39e634..4bf8a83a 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -20,7 +20,8 @@
*
*/
-#define DEBUG
+/* Uncomment to debug */
+/* #define DEBUG */
#include <stdint.h>
#include <stdio.h>
@@ -571,7 +572,7 @@ static void l1ctl_sim_req(struct msgb *msg)
uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
-#if 1 /* for debugging only */
+#ifdef DEBUG /* for debugging only */
{
int i;
printf("SIM Request (%u): ", len);
@@ -584,6 +585,53 @@ static void l1ctl_sim_req(struct msgb *msg)
sim_apdu(len, data);
}
+void l1ctl_tx_sim_up(uint8_t* atr, uint8_t atrLength)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_SIM_ATR);
+ uint8_t *data;
+ data = (uint8_t*) msgb_put(msg, atrLength);
+ memcpy(data, atr, atrLength);
+ msg->len += atrLength;
+
+ l1_queue_for_l2(msg);
+}
+
+static int powered_up = 0;
+
+static void l1ctl_rx_sim_powerup()
+{
+ uint8_t atr[20];
+ uint8_t atrLength = 0;
+
+ if (powered_up) {
+ puts("SIM: sim is already powered up, calling power down first!\n");
+ calypso_sim_powerdown();
+ }
+
+ memset(atr,0,sizeof(atr));
+
+ atrLength = calypso_sim_powerup(atr);
+ l1ctl_tx_sim_up(atr, atrLength);
+ powered_up = 1;
+}
+
+static void l1ctl_rx_sim_powerdown()
+{
+ calypso_sim_powerdown();
+ powered_up = 0;
+}
+
+static void l1ctl_rx_sim_reset()
+{
+ uint8_t atr[20];
+ uint8_t atrLength = 0;
+
+ memset(atr,0,sizeof(atr));
+
+ atrLength = calypso_sim_reset(atr);
+ l1ctl_tx_sim_up(atr, atrLength);
+}
+
static struct llist_head l23_rx_queue = LLIST_HEAD_INIT(l23_rx_queue);
/* callback from SERCOMM when L2 sends a message to L1 */
@@ -675,6 +723,15 @@ void l1a_l23_handler(void)
case L1CTL_SIM_REQ:
l1ctl_sim_req(msg);
break;
+ case L1CTL_SIM_POWERUP:
+ l1ctl_rx_sim_powerup();
+ break;
+ case L1CTL_SIM_POWERDOWN:
+ l1ctl_rx_sim_powerdown();
+ break;
+ case L1CTL_SIM_RESET:
+ l1ctl_rx_sim_reset();
+ break;
}
exit_msgbfree: