From 0856c8a6a5ad48d810da598b421f81fc21d0ba55 Mon Sep 17 00:00:00 2001 From: "Andreas.Eversberg" Date: Sat, 18 Sep 2010 19:15:15 +0000 Subject: [PATCH] [layer23] SIM client completion The SIM client is now complete. Because it usefull for multiple applications, i moved it to the layer23/src/common directory. The SIM reader works together with mobile process. Fixes were made. Thanx to all for testing, finding bugs, and making it work as it is supposed to do. The current version uses special L1CTL messages to send and receive APDUs. This will change in the future, when BTSAP interface is completed. Please note that this client will not work until the layer1 SIM reader fixes and extensions are committed. --- include/l1ctl_proto.h | 2 + .../layer23/include/osmocom/bb/common/l1ctl.h | 2 + .../include/osmocom/bb/common/osmocom_data.h | 2 +- .../osmocom/bb/{mobile => common}/sim.h | 3 +- src/host/layer23/src/common/Makefile.am | 2 +- src/host/layer23/src/common/l1ctl.c | 36 +++++ src/host/layer23/src/{mobile => common}/sim.c | 126 ++++++++++++------ src/host/layer23/src/mobile/Makefile.am | 2 +- src/host/layer23/src/mobile/app_mobile.c | 21 ++- src/host/layer23/src/mobile/gsm322.c | 6 +- src/host/layer23/src/mobile/subscriber.c | 32 +++-- 11 files changed, 161 insertions(+), 73 deletions(-) rename src/host/layer23/include/osmocom/bb/{mobile => common}/sim.h (98%) rename src/host/layer23/src/{mobile => common}/sim.c (91%) diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h index d76614b..80687a1 100644 --- a/include/l1ctl_proto.h +++ b/include/l1ctl_proto.h @@ -47,6 +47,8 @@ enum { L1CTL_PARAM_REQ, L1CTL_DM_FREQ_REQ, L1CTL_CRYPTO_REQ, + L1CTL_SIM_REQ, + L1CTL_SIM_CONF, }; enum ccch_mode { diff --git a/src/host/layer23/include/osmocom/bb/common/l1ctl.h b/src/host/layer23/include/osmocom/bb/common/l1ctl.h index 01a49b2..189df89 100644 --- a/src/host/layer23/include/osmocom/bb/common/l1ctl.h +++ b/src/host/layer23/include/osmocom/bb/common/l1ctl.h @@ -56,4 +56,6 @@ int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type); int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from, uint16_t arfcm_to); +int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length); + #endif 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 d953828..7ffbfd9 100644 --- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h +++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h @@ -18,7 +18,7 @@ struct osmocom_ms; #include #include #include -#include +#include /* A layer2 entity */ struct osmol2_entity { diff --git a/src/host/layer23/include/osmocom/bb/mobile/sim.h b/src/host/layer23/include/osmocom/bb/common/sim.h similarity index 98% rename from src/host/layer23/include/osmocom/bb/mobile/sim.h rename to src/host/layer23/include/osmocom/bb/common/sim.h index be8b8b5..c1e6087 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/sim.h +++ b/src/host/layer23/include/osmocom/bb/common/sim.h @@ -187,7 +187,7 @@ struct sim_hdr { uint8_t seek_type_mode; /* in case of seek command */ }; -#define SIM_ALLOC_SIZE 128 +#define SIM_ALLOC_SIZE 512 #define SIM_ALLOC_HEADROOM 64 struct msgb *gsm_sim_msgb_alloc(uint32_t handle, uint8_t job_type); @@ -266,6 +266,7 @@ struct gsm1111_ef_adn { uint8_t ext_id; } __attribute__ ((packed)); +int sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg); int gsm_sim_init(struct osmocom_ms *ms); int gsm_sim_exit(struct osmocom_ms *ms); int gsm_sim_job_dequeue(struct osmocom_ms *ms); diff --git a/src/host/layer23/src/common/Makefile.am b/src/host/layer23/src/common/Makefile.am index 1dadb51..b9019bb 100644 --- a/src/host/layer23/src/common/Makefile.am +++ b/src/host/layer23/src/common/Makefile.am @@ -3,4 +3,4 @@ AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) noinst_LIBRARIES = liblayer23.a liblayer23_a_SOURCES = l1ctl.c l1l2_interface.c sap_interface.c lapdm.c \ - logging.c networks.c + logging.c networks.c sim.c diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c index abf4f8e..72ccd5f 100644 --- a/src/host/layer23/src/common/l1ctl.c +++ b/src/host/layer23/src/common/l1ctl.c @@ -157,6 +157,7 @@ static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg) meas->rxlev += dl->rx_level; if (dl->num_biterr) { +printf("Dropping frame with %u bit errors\n", dl->num_biterr); LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n", dl->num_biterr); return 0; @@ -521,6 +522,38 @@ int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len) return osmo_send_l1(ms, msg); } +int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length) +{ + struct msgb *msg; + uint8_t *dat; + + msg = osmo_l1_alloc(L1CTL_SIM_REQ); + if (!msg) + return -1; + + dat = msgb_put(msg, length); + memcpy(dat, data, length); + + 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) +{ + uint16_t len = msg->len - sizeof(struct l1ctl_hdr); + uint8_t *data = msg->data + sizeof(struct l1ctl_hdr); + + printf("SIM %s\n", hexdump(data, len)); + + /* pull the L1 header from the msgb */ + msgb_pull(msg, sizeof(struct l1ctl_hdr)); + msg->l1h = NULL; + + sim_apdu_resp(ms, 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) @@ -657,6 +690,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) rc = rx_l1_ccch_mode_conf(ms, msg); msgb_free(msg); break; + case L1CTL_SIM_CONF: + rc = rx_l1_sim_conf(ms, msg); + break; default: fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type); msgb_free(msg); diff --git a/src/host/layer23/src/mobile/sim.c b/src/host/layer23/src/common/sim.c similarity index 91% rename from src/host/layer23/src/mobile/sim.c rename to src/host/layer23/src/common/sim.c index d4d1821..543292e 100644 --- a/src/host/layer23/src/mobile/sim.c +++ b/src/host/layer23/src/common/sim.c @@ -27,6 +27,7 @@ #include #include +#include extern void *l23_ctx; static int sim_process_job(struct osmocom_ms *ms); @@ -146,7 +147,8 @@ void gsm_sim_reply(struct osmocom_ms *ms, uint8_t result_type, uint8_t *result, uint16_t payload_len; struct gsm_sim_handler *handler; - LOGP(DSIM, LOGL_INFO, "sending result to callback function\n"); + LOGP(DSIM, LOGL_INFO, "sending result to callback function " + "(type=%d)\n", result_type); /* if no handler, or no callback, just free the job */ sh = (struct sim_hdr *)msg->data; @@ -181,10 +183,9 @@ void gsm_sim_reply(struct osmocom_ms *ms, uint8_t result_type, uint8_t *result, /* send APDU to card reader */ static int sim_apdu_send(struct osmocom_ms *ms, uint8_t *data, uint16_t length) { - // FIXME: send apdu to layer 1 LOGP(DSIM, LOGL_INFO, "sending APDU (class 0x%02x, ins 0x%02x)\n", data[0], data[1]); - printf("process stops here, because no APDU is exchanged with layer 1\n"); + l1ctl_tx_sim_req(ms, data, length); return 0; } @@ -673,32 +674,44 @@ static int sim_process_job(struct osmocom_ms *ms) // FIXME: send reset command to L1 } - /* check MF / DF */ - i = 0; - while (sh->path[i] && sim->path[i]) { - if (sh->path[i] != sh->path[i]) - break; - i++; - } - /* if path in message is shorter or if paths are different */ - if (sim->path[i]) { - LOGP(DSIM, LOGL_INFO, "wrong DF, go MF\n"); - sim->job_state = SIM_JST_SELECT_MFDF; - /* go MF */ - sim->path[0] = 0; - return gsm1111_tx_select(ms, 0x3f00); - } - /* if path in message is longer */ - if (sh->path[i]) { - LOGP(DSIM, LOGL_INFO, "requested path is longer, go child %s\n", - get_df_name(sh->path[i])); - sim->job_state = SIM_JST_SELECT_MFDF; - /* select child */ - sim->path[i] = sh->path[i]; - sim->path[i + 1] = 0; - return gsm1111_tx_select(ms, sh->path[i]); + /* navigate to right DF */ + switch (sh->job_type) { + case SIM_JOB_READ_BINARY: + case SIM_JOB_UPDATE_BINARY: + case SIM_JOB_READ_RECORD: + case SIM_JOB_UPDATE_RECORD: + case SIM_JOB_SEEK_RECORD: + case SIM_JOB_INCREASE: + case SIM_JOB_INVALIDATE: + case SIM_JOB_REHABILITATE: + case SIM_JOB_RUN_GSM_ALGO: + /* check MF / DF */ + i = 0; + while (sh->path[i] && sim->path[i]) { + if (sh->path[i] != sh->path[i]) + break; + i++; + } + /* if path in message is shorter or if paths are different */ + if (sim->path[i]) { + LOGP(DSIM, LOGL_INFO, "go MF\n"); + sim->job_state = SIM_JST_SELECT_MFDF; + /* go MF */ + sim->path[0] = 0; + return gsm1111_tx_select(ms, 0x3f00); + } + /* if path in message is longer */ + if (sh->path[i]) { + LOGP(DSIM, LOGL_INFO, "requested path is longer, go " + "child %s\n", get_df_name(sh->path[i])); + sim->job_state = SIM_JST_SELECT_MFDF; + /* select child */ + sim->path[i] = sh->path[i]; + sim->path[i + 1] = 0; + return gsm1111_tx_select(ms, sh->path[i]); + } + /* if paths are equal, continue */ } - /* if paths are equal, continue */ /* set state and trigger SIM process */ switch (sh->job_type) { @@ -711,6 +724,7 @@ static int sim_process_job(struct osmocom_ms *ms) case SIM_JOB_INVALIDATE: case SIM_JOB_REHABILITATE: sim->job_state = SIM_JST_SELECT_EF; + sim->file = sh->file; return gsm1111_tx_select(ms, sh->file); case SIM_JOB_RUN_GSM_ALGO: if (payload_len != 16) { @@ -806,7 +820,7 @@ static int sim_process_job(struct osmocom_ms *ms) } /* receive SIM response */ -static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) +int sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg) { struct gsm_sim *sim = &ms->sim; uint8_t *payload; @@ -815,6 +829,7 @@ static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) int length = msg->len, ef_len; uint8_t sw1, sw2; uint8_t cause; + uint8_t pin_cause[2]; struct sim_hdr *sh; struct gsm1111_response_ef *ef; struct gsm1111_response_mfdf *mfdf; @@ -845,6 +860,13 @@ static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) length, sw1, sw2); switch (sw1) { + case GSM1111_STAT_SECURITY: + LOGP(DSIM, LOGL_NOTICE, "SIM Security\n"); + pin_cause[0] = SIM_CAUSE_PIN1_REQUIRED; + pin_cause[1] = 1; /* PIN retries left */ + gsm_sim_reply(ms, SIM_JOB_ERROR, pin_cause, 2); + msgb_free(msg); + return 0; case GSM1111_STAT_MEM_PROBLEM: if (sw2 >= 0x40) { LOGP(DSIM, LOGL_NOTICE, "memory of SIM failed\n"); @@ -917,23 +939,36 @@ static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) } mfdf = (struct gsm1111_response_mfdf *)data; mfdf_gsm = (struct gsm1111_response_mfdf_gsm *)(data + 13); - /* if MF was selected, but MF is not indicated */ - if (ntohs(mfdf->file_id) != 0x3f00 && sim->path[0] == 0) { - goto sim_error; - } - /* if MF was selected, but type is not indicated */ - if (mfdf->tof != GSM1111_TOF_MF && sim->path[0]) { - goto sim_error; + /* if MF was selected */ + if (sim->path[0] == 0) { + /* if MF was selected, but MF is not indicated */ + if (ntohs(mfdf->file_id) != 0x3f00) { + LOGP(DSIM, LOGL_NOTICE, "Not MF\n"); + goto sim_error; + } + /* if MF was selected, but type is not indicated */ + if (mfdf->tof != GSM1111_TOF_MF) { + LOGP(DSIM, LOGL_NOTICE, "MF %02x != %02x " + "%04x\n", mfdf->tof, GSM1111_TOF_MF, + sim->path[0]); + goto sim_error; + } + /* now continue */ + msgb_free(msg); + return sim_process_job(ms); } /* if DF was selected, but this DF is not indicated */ i = 0; while (sim->path[i + 1]) i++; if (ntohs(mfdf->file_id) != sim->path[i]) { + LOGP(DSIM, LOGL_NOTICE, "Path %04x != %04x\n", + ntohs(mfdf->file_id), sim->path[i]); goto sim_error; } /* if DF was selected, but type is not indicated */ if (mfdf->tof != GSM1111_TOF_DF) { + LOGP(DSIM, LOGL_NOTICE, "TOF error\n"); goto sim_error; } /* now continue */ @@ -960,6 +995,8 @@ static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) ef = (struct gsm1111_response_ef *)data; /* if EF was selected, but type is not indicated */ if (ntohs(ef->file_id) != sim->file) { + LOGP(DSIM, LOGL_NOTICE, "EF ID %04x != %04x\n", + ntohs(ef->file_id), sim->file); goto sim_error; } /* get length of file */ @@ -973,27 +1010,27 @@ static int sim_apdu_receive(struct osmocom_ms *ms, struct msgb *msg) break; case SIM_JOB_UPDATE_BINARY: // FIXME: do chunks when greater or equal 256 bytes */ - if (ef_len < length) { + if (ef_len < payload_len) { LOGP(DSIM, LOGL_NOTICE, "selected file is " "smaller (%d) than data to update " - "(%d)\n", ef_len, length); + "(%d)\n", ef_len, payload_len); goto request_error; } - gsm1111_tx_update_binary(ms, 0, data, length); + gsm1111_tx_update_binary(ms, 0, payload, payload_len); break; case SIM_JOB_READ_RECORD: gsm1111_tx_read_record(ms, sh->rec_no, sh->rec_mode, ef_len); break; case SIM_JOB_UPDATE_RECORD: - if (ef_len != length) { + if (ef_len != payload_len) { LOGP(DSIM, LOGL_NOTICE, "selected file length " "(%d) does not equal record to update " - "(%d)\n", ef_len, length); + "(%d)\n", ef_len, payload_len); goto request_error; } gsm1111_tx_update_record(ms, sh->rec_no, sh->rec_mode, - data, length); + payload, payload_len); break; case SIM_JOB_SEEK_RECORD: gsm1111_tx_seek(ms, sh->seek_type_mode, data, length); @@ -1112,8 +1149,9 @@ int gsm_sim_init(struct osmocom_ms *ms) { struct gsm_sim *sim = &ms->sim; - /* current path is root (MF), no file selected */ - sim->path[0] = 0; + /* current path is undefined, forching MF */ + sim->path[0] = 0x0bad; + sim->path[1] = 0; sim->file = 0; INIT_LLIST_HEAD(&sim->handlers); diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am index b5d910a..055b3c2 100644 --- a/src/host/layer23/src/mobile/Makefile.am +++ b/src/host/layer23/src/mobile/Makefile.am @@ -4,7 +4,7 @@ LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) noinst_LIBRARIES = libmobile.a libmobile_a_SOURCES = gsm322.c gsm48_cc.c gsm48_mm.c gsm48_rr.c \ - mnccms.c settings.c subscriber.c support.c gps.c sim.c \ + mnccms.c settings.c subscriber.c support.c gps.c \ sysinfo.c transaction.c vty_interface.c bin_PROGRAMS = mobile diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c index 154768b..80cd26b 100644 --- a/src/host/layer23/src/mobile/app_mobile.c +++ b/src/host/layer23/src/mobile/app_mobile.c @@ -101,20 +101,17 @@ static int signal_cb(unsigned int subsys, unsigned int signal, set->test_rplmn_mnc); break; default: - /* no SIM */ - ; + /* no SIM, trigger PLMN selection process */ + nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON); + if (!nmsg) + return -ENOMEM; + gsm322_plmn_sendmsg(ms, nmsg); + nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON); + if (!nmsg) + return -ENOMEM; + gsm322_cs_sendmsg(ms, nmsg); } - /* start PLMN + cell selection process */ - nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON); - if (!nmsg) - return -ENOMEM; - gsm322_plmn_sendmsg(ms, nmsg); - nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON); - if (!nmsg) - return -ENOMEM; - gsm322_cs_sendmsg(ms, nmsg); - mobile_started = 1; } return 0; diff --git a/src/host/layer23/src/mobile/gsm322.c b/src/host/layer23/src/mobile/gsm322.c index fbeff2a..fb8b85b 100644 --- a/src/host/layer23/src/mobile/gsm322.c +++ b/src/host/layer23/src/mobile/gsm322.c @@ -2962,8 +2962,8 @@ static int gsm322_c_switch_on(struct osmocom_ms *ms, struct msgb *msg) if (!subscr->sim_valid) { LOGP(DCS, LOGL_INFO, "Switch on without SIM.\n"); return gsm322_c_any_cell_sel(ms, msg); - LOGP(DCS, LOGL_INFO, "Switch on with SIM inserted.\n"); } + LOGP(DCS, LOGL_INFO, "Switch on with SIM inserted.\n"); /* stay in NULL state until PLMN is selected */ @@ -2990,7 +2990,7 @@ static struct plmnastatelist { {ALL_STATES, GSM322_EVENT_SWITCH_OFF, gsm322_a_switch_off}, - {SBIT(GSM322_A6_NO_SIM), + {SBIT(GSM322_A0_NULL) | SBIT(GSM322_A6_NO_SIM), GSM322_EVENT_SIM_INSERT, gsm322_a_switch_on}, {ALL_STATES, @@ -3099,7 +3099,7 @@ static struct plmnmstatelist { {ALL_STATES, GSM322_EVENT_SWITCH_OFF, gsm322_m_switch_off}, - {SBIT(GSM322_M5_NO_SIM), + {SBIT(GSM322_M0_NULL) | SBIT(GSM322_M5_NO_SIM), GSM322_EVENT_SIM_INSERT, gsm322_m_switch_on}, {ALL_STATES, diff --git a/src/host/layer23/src/mobile/subscriber.c b/src/host/layer23/src/mobile/subscriber.c index fce62f0..b95858f 100644 --- a/src/host/layer23/src/mobile/subscriber.c +++ b/src/host/layer23/src/mobile/subscriber.c @@ -63,12 +63,12 @@ static char *sim_decode_bcd(uint8_t *data, uint8_t length) for (i = 0; i < (length << 1); i++) { if ((i & 1)) - c = (data[i >> 1] >> 4) + '0'; + c = (data[i >> 1] >> 4); else - c = (data[i >> 1] & 0xf) + '0'; + c = (data[i >> 1] & 0xf); if (c == 0xf) break; - result[j++] = c; + result[j++] = c + '0'; if (j == sizeof(result) - 1) break; } @@ -229,6 +229,7 @@ static int subscr_sim_imsi(struct osmocom_ms *ms, uint8_t *data, uint8_t length) { struct gsm_subscriber *subscr = &ms->subscr; + char *imsi; /* get actual length */ if (length < 1) @@ -238,14 +239,16 @@ static int subscr_sim_imsi(struct osmocom_ms *ms, uint8_t *data, return -EINVAL; } length = data[0]; - if ((length << 1) > GSM_IMSI_LENGTH - 1 || (length << 1) < 6) { + + /* decode IMSI, skip first digit (parity) */ + imsi = sim_decode_bcd(data + 1, length); + if (strlen(imsi) - 1 > GSM_IMSI_LENGTH - 1 || strlen(imsi) - 1 < 6) { LOGP(DMM, LOGL_NOTICE, "IMSI invalid length = %d\n", - length << 1); + strlen(imsi) - 1); return -EINVAL; } - strncpy(subscr->imsi, sim_decode_bcd(data + 1, length), - sizeof(subscr->imsi - 1)); + strncpy(subscr->imsi, imsi + 1, sizeof(subscr->imsi) - 1); LOGP(DMM, LOGL_INFO, "received IMSI %s from SIM\n", subscr->imsi); @@ -281,7 +284,9 @@ static int subscr_sim_loci(struct osmocom_ms *ms, uint8_t *data, subscr->ustate = GSM_SIM_U2_NOT_UPDATED; } - LOGP(DMM, LOGL_INFO, "received LOCI from SIM\n"); + LOGP(DMM, LOGL_INFO, "received LOCI from SIM (mcc=%s mnc=%s lac=0x%04x " + "U%d)\n", gsm_print_mcc(subscr->mcc), + gsm_print_mnc(subscr->mnc), subscr->lac, subscr->ustate); return 0; } @@ -386,8 +391,8 @@ static int subscr_sim_hpplmn(struct osmocom_ms *ms, uint8_t *data, /* HPLMN search interval */ subscr->t6m_hplmn = *data; /* multiple of 6 minutes */ - LOGP(DMM, LOGL_INFO, "received HPPLMN %d from SIM\n", - subscr->t6m_hplmn); + LOGP(DMM, LOGL_INFO, "received HPPLMN %d (%d mins) from SIM\n", + subscr->t6m_hplmn, subscr->t6m_hplmn * 6); return 0; } @@ -578,6 +583,12 @@ static void subscr_sim_query_cb(struct osmocom_ms *ms, struct msgb *msg) vty_notify(ms, "PIN is blocked\n"); break; default: + if (!subscr_sim_files[subscr->sim_file_index]. + mandatory) { + LOGP(DMM, LOGL_NOTICE, "SIM reading failed, " + "ignoring!\n"); + goto ignore; + } LOGP(DMM, LOGL_NOTICE, "SIM reading failed\n"); vty_notify(ms, NULL); @@ -604,6 +615,7 @@ static void subscr_sim_query_cb(struct osmocom_ms *ms, struct msgb *msg) } } +ignore: msgb_free(msg); /* trigger next file */ -- 2.20.1