diff options
author | Luca Melette <luca@srlabs.de> | 2013-12-25 17:28:18 +0100 |
---|---|---|
committer | Luca Melette <luca@srlabs.de> | 2013-12-25 17:28:18 +0100 |
commit | d88025e6d95f262aeccf2601ef27f17691866eb0 (patch) | |
tree | b5f8bdc69bc52b202c463ca1983bd6c9d4ecb1d0 /src/host/layer23 | |
parent | 2d0a5acaf3f3a7045475914832eb5ea0af7b203e (diff) |
Initial release of libosmosim, firmware and host code to support gsmmap.org toolsluca/libosmosim
Diffstat (limited to 'src/host/layer23')
-rw-r--r-- | src/host/layer23/configure.ac | 9 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/common/l1ctl.h | 3 | ||||
-rw-r--r-- | src/host/layer23/src/Makefile.am | 2 | ||||
-rw-r--r-- | src/host/layer23/src/common/l1ctl.c | 57 | ||||
-rw-r--r-- | src/host/layer23/src/libosmosim/Makefile.am | 7 | ||||
-rw-r--r-- | src/host/layer23/src/libosmosim/libosmosim.c | 296 | ||||
-rw-r--r-- | src/host/layer23/src/libosmosim/libosmosim.h | 9 |
7 files changed, 378 insertions, 5 deletions
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(); |