summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Golde <nico@ngolde.de>2011-05-23 09:18:26 +0200
committerNico Golde <nico@ngolde.de>2011-05-23 09:18:26 +0200
commit9eeff416b41c8699b24802e56b0caad72cb012ef (patch)
treea6120010f622878ed3296f79f2b8048bd60fe1db
parenta5611f9555fb288149c01371411a1405aa61056e (diff)
[SAP] implement simple SAP client to be used with the SAP server in the softsim repository
- this also introduces a new vty command to set the socket path before issueing sim reader ms
-rw-r--r--src/host/layer23/include/osmocom/bb/common/osmocom_data.h2
-rw-r--r--src/host/layer23/include/osmocom/bb/common/sap_interface.h65
-rw-r--r--src/host/layer23/src/common/l1ctl.c10
-rw-r--r--src/host/layer23/src/common/main.c10
-rw-r--r--src/host/layer23/src/common/sap_interface.c500
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c10
-rw-r--r--src/host/layer23/src/mobile/main.c2
-rw-r--r--src/host/layer23/src/mobile/settings.c2
-rw-r--r--src/host/layer23/src/mobile/vty_interface.c36
9 files changed, 570 insertions, 67 deletions
diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
index 9d8a030..5d41c99 100644
--- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
+++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
@@ -29,6 +29,8 @@ struct osmol2_entity {
struct osmosap_entity {
osmosap_cb_t msg_handler;
+ uint8_t sap_state;
+ uint16_t max_msg_size;
};
/* RX measurement statistics */
diff --git a/src/host/layer23/include/osmocom/bb/common/sap_interface.h b/src/host/layer23/include/osmocom/bb/common/sap_interface.h
index f2f577a..95d7d51 100644
--- a/src/host/layer23/include/osmocom/bb/common/sap_interface.h
+++ b/src/host/layer23/include/osmocom/bb/common/sap_interface.h
@@ -5,7 +5,70 @@ typedef int (*osmosap_cb_t)(struct msgb *msg, struct osmocom_ms *ms);
int sap_open(struct osmocom_ms *ms, const char *socket_path);
int sap_close(struct osmocom_ms *ms);
-int osmosap_send(struct osmocom_ms *ms, struct msgb *msg);
+int osmosap_send_apdu(struct osmocom_ms *ms, struct msgb *msg);
int osmosap_register_handler(struct osmocom_ms *ms, osmosap_cb_t cb);
+int osmosap_sapsocket(struct osmocom_ms *ms, const char *path);
+int osmosap_init(struct osmocom_ms *ms);
+
+enum osmosap_state {
+ SAP_NOT_CONNECTED,
+ SAP_IDLE,
+ SAP_CONNECTION_UNDER_NEGOTIATION,
+ SAP_PROCESSING_ATR_REQUEST,
+ SAP_PROCESSING_APDU_REQUEST
+};
+
+/* BTSAP 1.13 */
+enum osmosap_msg_type {
+ SAP_CONNECT_REQ = 0x00,
+ SAP_CONNECT_RESP = 0x01,
+ SAP_DISCONNECT_REQ = 0x02,
+ SAP_DISCONNECT_RESP = 0x03,
+ SAP_DISCONNECT_IND = 0x04,
+ SAP_TRANSFER_APDU_REQ = 0x05,
+ SAP_TRANSFER_APDU_RESP = 0x06,
+ SAP_TRANSFER_ATR_REQ = 0x07,
+ SAP_TRANSFER_ATR_RESP = 0x08,
+ SAP_POWER_SIM_OFF_REQ = 0x09,
+ SAP_POWER_SIM_OFF_RESP = 0x0A,
+ SAP_POWER_SIM_ON_REQ = 0x0B,
+ SAP_POWER_SIM_ON_RESP = 0x0C,
+ SAP_RESET_SIM_REQ = 0x0D,
+ SAP_RESET_SIM_RESP = 0x0E,
+ SAP_TRANSFER_CARD_READER_STATUS_REQ = 0x0F,
+ SAP_TRANSFER_CARD_READER_STATUS_RESP = 0x10,
+ SAP_STATUS_IND = 0x11,
+ SAP_ERROR_RESP = 0x12,
+ SAP_SET_TRANSPORT_PROTOCOL_REQ = 0x13,
+ SAP_SET_TRANSPORT_PROTOCOL_RESP = 0x14
+};
+
+/* BTSAP 5.2 */
+enum osmosap_param_type {
+ SAP_MAX_MSG_SIZE = 0x00,
+ SAP_CONNECTION_STATUS = 0x01,
+ SAP_RESULT_CODE = 0x02,
+ SAP_DISCONNECTION_TYPE = 0x03,
+ SAP_COMMAND_APDU = 0x04,
+ SAP_COMMAND_APDU_7816 = 0x10,
+ SAP_RESPONSE_APDU = 0x05,
+ SAP_ATR = 0x06,
+ SAP_CARD_READER_STATUS = 0x07,
+ SAP_STATUS_CHANGE = 0x08,
+ SAP_TRANSPORT_PROTOCOL = 0x09
+};
+
+struct sap_param {
+ uint8_t id;
+ uint16_t len;
+ uint8_t *value;
+};
+
+struct sap_msg {
+ uint8_t id;
+ uint8_t num_params;
+ struct sap_param *params;
+};
+
#endif /* _SAP_INTERFACE_H */
diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c
index f2714e6..6061ba6 100644
--- a/src/host/layer23/src/common/l1ctl.c
+++ b/src/host/layer23/src/common/l1ctl.c
@@ -595,7 +595,15 @@ int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
dat = msgb_put(msg, length);
memcpy(dat, data, length);
- return osmo_send_l1(ms, msg);
+ /* strip l1 header, we want to dump the raw apdu into the socket */
+ msgb_pull(msg, sizeof(struct l1ctl_hdr));
+ msg->l1h = NULL;
+ LOGP(DSIM, LOGL_INFO, "Sending: '%s'\n", hexdump(msg->data, msg->len));
+
+ if(ms->settings.sap_socket_path[0] == 0)
+ return osmo_send_l1(ms, msg);
+ else
+ return osmosap_send_apdu(ms, msg);
}
/* just forward the SIM response to the SIM handler */
diff --git a/src/host/layer23/src/common/main.c b/src/host/layer23/src/common/main.c
index 61513ea..d82d435 100644
--- a/src/host/layer23/src/common/main.c
+++ b/src/host/layer23/src/common/main.c
@@ -251,9 +251,13 @@ int main(int argc, char **argv)
exit(1);
}
- rc = sap_open(ms, sap_socket_path);
- if (rc < 0)
- fprintf(stderr, "Failed during sap_open(), no SIM reader\n");
+ if(sap_socket_path){
+ rc = sap_open(ms, sap_socket_path);
+ if (rc < 0){
+ fprintf(stderr, "Failed during sap_open(), no SIM reader\n");
+ exit(1);
+ }
+ }
lapdm_init(&ms->l2_entity.lapdm_dcch, ms);
lapdm_init(&ms->l2_entity.lapdm_acch, ms);
diff --git a/src/host/layer23/src/common/sap_interface.c b/src/host/layer23/src/common/sap_interface.c
index 54aa635..1492cb1 100644
--- a/src/host/layer23/src/common/sap_interface.c
+++ b/src/host/layer23/src/common/sap_interface.c
@@ -3,6 +3,7 @@
/* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2011 by Nico Golde <nico@ngolde.de>
*
* All Rights Reserved
*
@@ -27,6 +28,7 @@
#include <osmocom/bb/common/sap_interface.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -42,45 +44,363 @@
#define GSM_SAP_LENGTH 300
#define GSM_SAP_HEADROOM 32
-static int sap_read(struct bsc_fd *fd)
+static void sap_connect(struct osmocom_ms *ms);
+
+static const struct value_string sap_param_names[] = {
+ {SAP_MAX_MSG_SIZE, "MaxMsgSize"},
+ {SAP_CONNECTION_STATUS, "ConnectionStatus"},
+ {SAP_RESULT_CODE, "ResultCode"},
+ {SAP_DISCONNECTION_TYPE, "DisconnectionType"},
+ {SAP_COMMAND_APDU, "CommandAPDU"},
+ {SAP_COMMAND_APDU_7816, "CommandAPDU7816"},
+ {SAP_RESPONSE_APDU, "ResponseAPDU"},
+ {SAP_ATR, "ATR"},
+ {SAP_CARD_READER_STATUS, "CardReaderStatus"},
+ {SAP_STATUS_CHANGE, "StatusChange"},
+ {SAP_TRANSPORT_PROTOCOL, "TransportProtocol"}
+};
+
+static const struct value_string sap_msg_names[] = {
+ {SAP_CONNECT_REQ, "CONNECT_REQ"},
+ {SAP_CONNECT_RESP, "CONNECT_RESP"},
+ {SAP_DISCONNECT_REQ, "DISCONNECT_REQ"},
+ {SAP_DISCONNECT_RESP, "DISCONNECT_RESP"},
+ {SAP_DISCONNECT_IND, "DISCONNECT_IND"},
+ {SAP_TRANSFER_APDU_REQ, "TRANSFER_APDU_REQ"},
+ {SAP_TRANSFER_APDU_RESP, "TRANSFER_APDU_RESP"},
+ {SAP_TRANSFER_ATR_REQ, "TRANSFER_ATR_REQ"},
+ {SAP_TRANSFER_ATR_RESP, "TRANSFER_ATR_RESP"},
+ {SAP_POWER_SIM_OFF_REQ, "POWER_SIM_OFF_REQ"},
+ {SAP_POWER_SIM_OFF_RESP, "POWER_SIM_OFF_RESP"},
+ {SAP_POWER_SIM_ON_REQ, "POWER_SIM_ON_REQ"},
+ {SAP_POWER_SIM_ON_RESP, "POWER_SIM_ON_RESP"},
+ {SAP_RESET_SIM_REQ, "RESET_SIM_REQ"},
+ {SAP_RESET_SIM_RESP, "RESET_SIM_RESP"},
+ {SAP_TRANSFER_CARD_READER_STATUS_REQ, "TRANSFER_CARD_READER_STATUS_REQ"},
+ {SAP_TRANSFER_CARD_READER_STATUS_RESP, "TRANSFER_CARD_READER_STATUS_RESP"},
+ {SAP_STATUS_IND, "STATUS_IND"},
+ {SAP_ERROR_RESP, "ERROR_RESP"},
+ {SAP_SET_TRANSPORT_PROTOCOL_REQ, "SET_TRANSPORT_PROTOCOL_REQ"},
+ {SAP_SET_TRANSPORT_PROTOCOL_RESP, "SET_TRANSPORT_PROTOCOL_RESP"}
+};
+
+/* BTSAP table 5.18 */
+static const struct value_string sap_result_names[] = {
+ {0, "OK, request processed correctly"},
+ {1, "Error, no reason defined"},
+ {2, "Error, card not accessible"},
+ {3, "Error, card (already) powered off"},
+ {4, "Error, card removed"},
+ {5, "Error, card already powered on"},
+ {6, "Error, data not available"},
+ {7, "Error, not supported"}
+};
+
+static const struct value_string sap_status_change_names[] = {
+ {0, "Unknown Error"},
+ {1, "Card reset"},
+ {2, "Card not accessible"},
+ {3, "Card removed"},
+ {4, "Card inserted"},
+ {5, "Card recovered"},
+};
+
+static const struct value_string sap_status_names[] = {
+ {0, "OK, Server can fulfill requirements"},
+ {1, "Error, Server unable to establish connection"},
+ {2, "Error, Server does not support maximum message size"},
+ {3, "Error, maximum message size by Client is too small"},
+ {4, "OK, ongoing call"}
+};
+
+static struct msgb *sap_create_msg(uint8_t id, uint8_t num_params, struct sap_param *params)
{
struct msgb *msg;
- u_int16_t len;
- int rc;
- struct osmocom_ms *ms = (struct osmocom_ms *) fd->data;
+ uint8_t *msgp;
+ uint8_t i, plen, padding = 0;
- msg = msgb_alloc_headroom(GSM_SAP_LENGTH+GSM_SAP_HEADROOM, GSM_SAP_HEADROOM, "Layer2");
+ msg = msgb_alloc(GSM_SAP_LENGTH, "osmosap");
if (!msg) {
LOGP(DSAP, LOGL_ERROR, "Failed to allocate msg.\n");
+ return NULL;
+ }
+
+ /* BTSAP 5.1 */
+ msgb_put_u8(msg, id);
+ msgb_put_u8(msg, num_params);
+ msgb_put_u16(msg, 0);
+
+ for(i=0; i<num_params; i++){
+ plen = params[i].len;
+ msgb_put_u8(msg, params[i].id);
+ msgb_put_u8(msg, 0);
+ msgb_put_u16(msg, plen);
+ if(plen % 4){
+ padding = 4 - (plen % 4);
+ }
+ msgp = msgb_put(msg, plen + padding);
+ memcpy(msgp, params[i].value, plen);
+
+ if(padding){
+ memset(msgp + plen, 0, padding);
+ }
+ }
+
+ return msg;
+}
+
+static int osmosap_send(struct osmocom_ms *ms, struct msgb *msg)
+{
+ if(ms->sap_entity.sap_state == SAP_NOT_CONNECTED && !ms->sap_entity.sap_state == SAP_CONNECTION_UNDER_NEGOTIATION)
+ sap_connect(ms);
+
+ if (ms->sap_wq.bfd.fd <= 0)
+ return -EINVAL;
+
+ if (write_queue_enqueue(&ms->sap_wq, msg) != 0) {
+ LOGP(DSAP, LOGL_ERROR, "Failed to enqueue msg.\n");
+ msgb_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sap_parse_result(struct sap_param *param)
+{
+ if(param->id != SAP_RESULT_CODE){
+ LOGP(DSAP, LOGL_INFO, "> Parameter id: %u no valid result type\n", param->id);
+ return -1;
+ } else {
+ LOGP(DSAP, LOGL_INFO, "> RESULT CODE: %s\n",
+ get_value_string(sap_result_names, param->value[0]));
+ }
+
+ if(param->value[0] > sizeof(sap_result_names)/sizeof(struct value_string)){
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint8_t *sap_get_param(uint8_t *data, struct sap_param *param)
+{
+ uint8_t *dptr = data;
+ uint8_t padlen;
+
+ param->id = *dptr++;
+ /* skip reserved byte */
+ dptr++;
+ param->len = *dptr << 8;
+ dptr++;
+ param->len |= *dptr++;
+ param->value = talloc_zero_size(NULL, param->len);
+ memcpy(param->value, dptr, param->len);
+
+ /* skip parameter and padding and return pointer to next parameter */
+ dptr += param->len;
+ if(param->len % 4){
+ padlen = (4 - param->len % 4);
+ } else {
+ padlen = 0;
+ }
+ dptr += padlen;
+
+ return dptr;
+}
+
+static void sap_msg_free(struct sap_msg *msg)
+{
+ uint8_t i;
+ for(i=0; i<msg->num_params; i++){
+ talloc_free(msg->params[i].value);
+ talloc_free(msg->params);
+ }
+ talloc_free(msg);
+}
+
+static struct sap_msg *sap_parse_msg(uint8_t *data)
+{
+ struct sap_msg *msg = talloc_zero(NULL, struct sap_msg);
+ uint8_t *ptr = data;
+ uint8_t i;
+
+ if(!msg){
+ return NULL;
+ }
+
+ msg->id = *ptr++;
+ LOGP(DSAP, LOGL_INFO, "> %s \n", get_value_string(sap_msg_names, msg->id));
+
+ msg->num_params = *ptr++;
+ /* skip two reserved null bytes, BTSAP 5.1 */
+ ptr += 2;
+
+ msg->params = talloc_zero_size(NULL, sizeof(struct sap_param) * msg->num_params);
+
+ for(i=0; i<msg->num_params; i++){
+ ptr = sap_get_param(ptr, &msg->params[i]);
+ LOGP(DSAP, LOGL_INFO, "> %s %s\n",
+ get_value_string(sap_param_names, msg->params[i].id),
+ hexdump(msg->params[i].value, msg->params[i].len));
+ }
+
+ return msg;
+}
+
+static void sap_apdu_resp(struct osmocom_ms *ms, uint8_t *data, uint16_t len)
+{
+ struct msgb *msg;
+ uint8_t *apdu;
+ msg = msgb_alloc(GSM_SAP_LENGTH, "osmosap");
+ if(!msg){
+ LOGP(DSAP, LOGL_ERROR, "Failed to allocate memory.\n");
+ return;
+ }
+
+ apdu = msgb_put(msg, len);
+ memcpy(apdu, data, len);
+
+ LOGP(DSAP, LOGL_DEBUG, "Forwarding APDU to SIM handler.\n");
+ sim_apdu_resp(ms, msg);
+}
+
+static int sap_adapt_msg_size(struct osmocom_ms *ms, struct sap_param *param)
+{
+ uint16_t size;
+ size = (param->value[0] << 8) | param->value[1];
+ if(size != ms->sap_entity.max_msg_size && size > 0){
+ LOGP(DSAP, LOGL_NOTICE, "Server can not handle max_msg_size, adapting.\n");
+ ms->sap_entity.max_msg_size = size;
+ return -1;
+ }
+ return 0;
+}
+
+static void sap_atr(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+ if(ms->sap_entity.sap_state != SAP_IDLE){
+ LOGP(DSAP, LOGL_ERROR, "Attempting to send ATR request while not being idle.\n");
+ return;
+ }
+
+ msg = sap_create_msg(SAP_TRANSFER_ATR_REQ, 0, NULL);
+ if(!msg)
+ return;
+
+ osmosap_send(ms, msg);
+ ms->sap_entity.sap_state = SAP_PROCESSING_ATR_REQUEST;
+}
+
+static void sap_parse_resp(struct osmocom_ms *ms, uint8_t *data, uint16_t len)
+{
+ struct sap_msg *msg = NULL;
+ if(len > ms->sap_entity.max_msg_size){
+ LOGP(DSAP, LOGL_ERROR, "Read more data than allowed by max_msg_size, ignoring.\n");
+ return;
+ }
+
+ msg = sap_parse_msg(data);
+ if(!msg){
+ sap_msg_free(msg);
+ return;
+ }
+
+ switch(msg->id){
+ case SAP_CONNECT_RESP:
+ LOGP(DSAP, LOGL_INFO, "Status: %s\n", get_value_string(sap_status_names, msg->params[0].value[0]));
+ if(msg->params[0].value[0] == 0){
+ ms->sap_entity.sap_state = SAP_IDLE;
+ }
+ if(msg->num_params == 2 && msg->params[1].len == 2){
+ if(sap_adapt_msg_size(ms, &msg->params[1]) < 0) {
+ ms->sap_entity.sap_state = SAP_NOT_CONNECTED;
+ } else {
+ sap_atr(ms);
+ }
+ }
+ break;
+ case SAP_DISCONNECT_RESP:
+ ms->sap_entity.sap_state = SAP_NOT_CONNECTED;
+ break;
+ case SAP_STATUS_IND:
+ LOGP(DSAP, LOGL_INFO, "New card state: %s\n", get_value_string(sap_status_change_names,
+ msg->params[0].value[0]));
+ if(msg->params[0].value[0] != 1){
+ /* TODO: handle case in which the card is not ready yet */
+ }
+ break;
+ case SAP_TRANSFER_ATR_RESP:
+ if(ms->sap_entity.sap_state != SAP_PROCESSING_ATR_REQUEST){
+ LOGP(DSAP, LOGL_ERROR, "got ATR resp in state: %u\n", ms->sap_entity.sap_state);
+ return;
+ }
+ if(msg->num_params >= 2){
+ LOGP(DSAP, LOGL_INFO, "ATR: %s\n", hexdump(msg->params[1].value, msg->params[1].len));
+ }
+ ms->sap_entity.sap_state = SAP_IDLE;
+ break;
+ case SAP_TRANSFER_APDU_RESP:
+ if(ms->sap_entity.sap_state != SAP_PROCESSING_APDU_REQUEST){
+ LOGP(DSAP, LOGL_ERROR, "got APDU resp in state: %u\n", ms->sap_entity.sap_state);
+ return;
+ }
+ if(msg->num_params != 2){
+ LOGP(DSAP, LOGL_ERROR, "wrong number of parameters %u in APDU response\n", msg->num_params);
+ return;
+ }
+ ms->sap_entity.sap_state = SAP_IDLE;
+ if(sap_parse_result(&msg->params[0]) == 0){
+ /* back apdu resp to layer23 */
+ sap_apdu_resp(ms, msg->params[1].value, msg->params[1].len);
+ }
+ break;
+ case SAP_ERROR_RESP:
+ if(ms->sap_entity.sap_state == SAP_CONNECTION_UNDER_NEGOTIATION){
+ ms->sap_entity.sap_state = SAP_NOT_CONNECTED;
+ } else {
+ ms->sap_entity.sap_state = SAP_IDLE;
+ }
+ break;
+ default:
+ LOGP(DSAP, LOGL_ERROR, "got unknown or not implemented SAP msgid: %u\n", msg->id);
+ break;
+ }
+}
+
+static int sap_read(struct bsc_fd *fd)
+{
+ struct msgb *msg = NULL;
+ struct osmocom_ms *ms = (struct osmocom_ms *) fd->data;
+ uint8_t *sap_buffer;
+ ssize_t rc;
+
+ sap_buffer = talloc_zero_size(NULL, ms->sap_entity.max_msg_size);
+ if(!sap_buffer){
+ fprintf(stderr, "Failed to allocate memory\n");
return -ENOMEM;
}
- rc = read(fd->fd, &len, sizeof(len));
- if (rc < sizeof(len)) {
+ rc = read(fd->fd, sap_buffer, ms->sap_entity.max_msg_size - 1);
+ if (rc < 0) {
fprintf(stderr, "SAP socket failed\n");
msgb_free(msg);
- if (rc >= 0)
- rc = -EIO;
sap_close(ms);
return rc;
}
-
- len = ntohs(len);
- if (len > GSM_SAP_LENGTH) {
- LOGP(DSAP, LOGL_ERROR, "Length is too big: %u\n", len);
+ if(rc == 0) {
+ fprintf(stderr, "SAP socket closed by server\n");
msgb_free(msg);
- return -EINVAL;
+ sap_close(ms);
+ return -ECONNREFUSED;
}
+ sap_buffer[rc] = 0;
+ LOGP(DSAP, LOGL_INFO, "Received %zd bytes: %s\n", rc, hexdump(sap_buffer, rc));
- msg->l1h = msgb_put(msg, len);
- rc = read(fd->fd, msg->l1h, msgb_l1len(msg));
- if (rc != msgb_l1len(msg)) {
- LOGP(DSAP, LOGL_ERROR, "Can not read data: len=%d rc=%d "
- "errno=%d\n", len, rc, errno);
- msgb_free(msg);
- return rc;
- }
+ sap_parse_resp(ms, sap_buffer, rc);
+ talloc_free(sap_buffer);
if (ms->sap_entity.msg_handler)
ms->sap_entity.msg_handler(msg, ms);
@@ -90,23 +410,93 @@ static int sap_read(struct bsc_fd *fd)
static int sap_write(struct bsc_fd *fd, struct msgb *msg)
{
- int rc;
+ ssize_t rc;
if (fd->fd <= 0)
return -EINVAL;
+ LOGP(DSAP, LOGL_INFO, "< %s\n", hexdump(msg->data, msg->len));
rc = write(fd->fd, msg->data, msg->len);
if (rc != msg->len) {
- LOGP(DSAP, LOGL_ERROR, "Failed to write data: rc: %d\n", rc);
+ LOGP(DSAP, LOGL_ERROR, "Failed to write data: rc: %zd\n", rc);
return rc;
}
return 0;
}
+static void sap_connect(struct osmocom_ms *ms)
+{
+ uint8_t buffer[3];
+ struct msgb *msg;
+ uint16_t size = ms->sap_entity.max_msg_size;
+ struct sap_param params[1];
+
+ params[0].id = SAP_MAX_MSG_SIZE;
+ params[0].len = 2;
+
+ if(ms->sap_entity.sap_state != SAP_NOT_CONNECTED) {
+ LOGP(DSAP, LOGL_ERROR, "Attempting to connect while there is an active connection.\n");
+ return;
+ }
+
+ buffer[0] = (size >> 8) & 0xFF;
+ buffer[1] = size & 0xFF;
+ buffer[2] = 0;
+ params[0].value = buffer;
+
+ msg = sap_create_msg(SAP_CONNECT_REQ, 1, params);
+ if(!msg)
+ return;
+
+ osmosap_send(ms, msg);
+
+ ms->sap_entity.sap_state = SAP_CONNECTION_UNDER_NEGOTIATION;
+}
+
+static void sap_disconnect(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+ if(ms->sap_entity.sap_state != SAP_NOT_CONNECTED && ms->sap_entity.sap_state != SAP_CONNECTION_UNDER_NEGOTIATION){
+ LOGP(DSAP, LOGL_ERROR, "Attempting to disconnect while no active connection.\n");
+ return;
+ }
+
+ msg = sap_create_msg(SAP_DISCONNECT_REQ, 0, NULL);
+ if(!msg)
+ return;
+
+ osmosap_send(ms, msg);
+
+ ms->sap_entity.sap_state = SAP_NOT_CONNECTED;
+}
+
+static void sap_apdu(struct osmocom_ms *ms, uint8_t *data, uint16_t len)
+{
+ struct msgb *msg;
+ struct sap_param params[1];
+
+ params[0].id = SAP_COMMAND_APDU;
+ params[0].len = len;
+ params[0].value = data;
+
+ if(ms->sap_entity.sap_state != SAP_IDLE){
+ LOGP(DSAP, LOGL_ERROR, "Attempting to send APDU request while not being idle.\n");
+ return;
+ }
+
+ msg = sap_create_msg(SAP_TRANSFER_APDU_REQ, 1, params);
+ if(!msg)
+ return;
+
+ osmosap_send(ms, msg);
+
+ ms->sap_entity.sap_state = SAP_PROCESSING_APDU_REQUEST;
+}
+
int sap_open(struct osmocom_ms *ms, const char *socket_path)
{
- int rc;
+ ssize_t rc;
struct sockaddr_un local;
ms->sap_wq.bfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -119,10 +509,9 @@ int sap_open(struct osmocom_ms *ms, const char *socket_path)
strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
local.sun_path[sizeof(local.sun_path) - 1] = '\0';
- rc = connect(ms->sap_wq.bfd.fd, (struct sockaddr *) &local,
- sizeof(local.sun_family) + strlen(local.sun_path));
+ rc = connect(ms->sap_wq.bfd.fd, (struct sockaddr *) &local, sizeof(local));
if (rc < 0) {
- fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
+ fprintf(stderr, "Failed to connect to '%s'\n", local.sun_path);
close(ms->sap_wq.bfd.fd);
return rc;
}
@@ -139,6 +528,8 @@ int sap_open(struct osmocom_ms *ms, const char *socket_path)
return rc;
}
+ sap_connect(ms);
+
return 0;
}
@@ -147,6 +538,7 @@ int sap_close(struct osmocom_ms *ms)
if (ms->sap_wq.bfd.fd <= 0)
return -EINVAL;
+ sap_disconnect(ms);
close(ms->sap_wq.bfd.fd);
ms->sap_wq.bfd.fd = -1;
bsc_unregister_fd(&ms->sap_wq.bfd);
@@ -154,35 +546,49 @@ int sap_close(struct osmocom_ms *ms)
return 0;
}
-int osmosap_send(struct osmocom_ms *ms, struct msgb *msg)
+int osmosap_send_apdu(struct osmocom_ms *ms, struct msgb *msg)
{
- uint16_t *len;
+ sap_apdu(ms, msg->data, msg->len);
- if (ms->sap_wq.bfd.fd <= 0)
- return -EINVAL;
+ return 0;
+}
- DEBUGP(DSAP, "Sending: '%s'\n", hexdump(msg->data, msg->len));
+/* register message handler for messages that are sent from L2->L3 */
+int osmosap_register_handler(struct osmocom_ms *ms, osmosap_cb_t cb)
+{
+ ms->sap_entity.msg_handler = cb;
- if (msg->l1h != msg->data)
- LOGP(DSAP, LOGL_ERROR, "Message SAP header != Message Data\n");
-
- /* prepend 16bit length before sending */
- len = (uint16_t *) msgb_push(msg, sizeof(*len));
- *len = htons(msg->len - sizeof(*len));
+ return 0;
+}
- if (write_queue_enqueue(&ms->sap_wq, msg) != 0) {
- LOGP(DSAP, LOGL_ERROR, "Failed to enqueue msg.\n");
- msgb_free(msg);
- return -1;
- }
+int osmosap_sapsocket(struct osmocom_ms *ms, const char *path)
+{
+ struct gsm_settings *set = &ms->settings;
+ memset(set->sap_socket_path, 0, sizeof(set->sap_socket_path));
+ strncpy(set->sap_socket_path, path, sizeof(set->sap_socket_path) - 1);
return 0;
}
-/* register message handler for messages that are sent from L2->L3 */
-int osmosap_register_handler(struct osmocom_ms *ms, osmosap_cb_t cb)
+/* init */
+int osmosap_init(struct osmocom_ms *ms)
{
- ms->sap_entity.msg_handler = cb;
+ struct osmosap_entity *sap = &ms->sap_entity;
+ int rc;
+
+ sap->sap_state = SAP_NOT_CONNECTED;
+ sap->max_msg_size = GSM_SAP_LENGTH;
+
+ LOGP(DSAP, LOGL_INFO, "init SAP client\n");
+
+ if(ms->settings.sap_socket_path){
+ rc = sap_open(ms, ms->settings.sap_socket_path);
+ if (rc < 0) {
+ fprintf(stderr, "Failed during sap_open(), no SIM reader\n");
+ ms->sap_wq.bfd.fd = -1;
+ return rc;
+ }
+ }
return 0;
}
diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index 33fdde6..05e5415 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -177,16 +177,6 @@ int mobile_init(struct osmocom_ms *ms)
return rc;
}
-#if 0
- rc = sap_open(ms, ms->settings.sap_socket_path);
- if (rc < 0) {
- fprintf(stderr, "Failed during sap_open(), no SIM reader\n");
- ms->sap_wq.bfd.fd = -1;
- mobile_exit(ms, 1);
- return rc;
- }
-#endif
-
if (mncc_recv_app)
ms->cclayer.mncc_recv = mncc_recv_app;
else if (ms->settings.ch_cap == GSM_CAP_SDCCH)
diff --git a/src/host/layer23/src/mobile/main.c b/src/host/layer23/src/mobile/main.c
index 4765995..d03f65c 100644
--- a/src/host/layer23/src/mobile/main.c
+++ b/src/host/layer23/src/mobile/main.c
@@ -167,7 +167,7 @@ int main(int argc, char **argv)
handle_options(argc, argv);
if (!debug_set)
- log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
+ log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM:DSAP");
log_set_log_level(stderr_target, LOGL_INFO);
if (gsmtap_ip) {
diff --git a/src/host/layer23/src/mobile/settings.c b/src/host/layer23/src/mobile/settings.c
index db22fd9..6e2338b 100644
--- a/src/host/layer23/src/mobile/settings.c
+++ b/src/host/layer23/src/mobile/settings.c
@@ -29,7 +29,6 @@
#include <osmocom/bb/common/networks.h>
static char *layer2_socket_path = "/tmp/osmocom_l2";
-static char *sap_socket_path = "/tmp/osmocom_sap";
int gsm_settings_init(struct osmocom_ms *ms)
{
@@ -37,7 +36,6 @@ int gsm_settings_init(struct osmocom_ms *ms)
struct gsm_support *sup = &ms->support;
strcpy(set->layer2_socket_path, layer2_socket_path);
- strcpy(set->sap_socket_path, sap_socket_path);
/* IMEI */
sprintf(set->imei, "000000000000000");
diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c
index 418c3f6..f1150b7 100644
--- a/src/host/layer23/src/mobile/vty_interface.c
+++ b/src/host/layer23/src/mobile/vty_interface.c
@@ -438,7 +438,7 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [MCC] [MNC] [LAC] [TMSI]",
return CMD_WARNING;
if (ms->subscr.sim_valid) {
- vty_out(vty, "SIM already presend, remove first!%s",
+ vty_out(vty, "SIM already present, remove first!%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -471,17 +471,27 @@ DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
"SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
{
struct osmocom_ms *ms;
+ struct gsm_settings *set = &ms->settings;
ms = get_ms(argv[0], vty);
if (!ms)
return CMD_WARNING;
if (ms->subscr.sim_valid) {
- vty_out(vty, "SIM already presend, remove first!%s",
+ vty_out(vty, "SIM already present, remove first!%s",
VTY_NEWLINE);
return CMD_WARNING;
}
+ if(access(set->sap_socket_path, F_OK) == 0){
+ if(osmosap_init(ms) != 0){
+ return CMD_WARNING;
+ }
+ } else {
+ /* this is only so we can check the first byte to be null in l1ctl_tx_sim_req */
+ set->sap_socket_path[0] = 0;
+ }
+
gsm_subscr_simcard(ms);
return CMD_SUCCESS;
@@ -652,6 +662,27 @@ DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
return CMD_SUCCESS;
}
+DEFUN(sim_sapsocket, sim_sapsocket_cmd, "sim sap-socket MS_NAME SOCKET_PATH",
+ "SIM actions\nEnter SAP socket used instead of SIM driver for card\nName of MS (see \"show ms\")\n"
+ "socket path")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if(!argv[1]){
+ vty_out(vty, "You must specify a SAP socket path%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+
+ osmosap_sapsocket(ms, (char *)argv[1]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
"Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
"Mobile Country Code\nMobile Network Code")
@@ -2296,6 +2327,7 @@ int ms_vty_init(void)
install_element(ENABLE_NODE, &sim_enable_pin_cmd);
install_element(ENABLE_NODE, &sim_change_pin_cmd);
install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
+ install_element(ENABLE_NODE, &sim_sapsocket_cmd);
install_element(ENABLE_NODE, &sim_lai_cmd);
install_element(ENABLE_NODE, &network_search_cmd);
install_element(ENABLE_NODE, &network_show_cmd);