diff options
-rw-r--r-- | include/l1ctl_proto.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/common/l1ctl.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/common/osmocom_data.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/common/sim.h (renamed from src/host/layer23/include/osmocom/bb/mobile/sim.h) | 3 | ||||
-rw-r--r-- | src/host/layer23/src/common/Makefile.am | 2 | ||||
-rw-r--r-- | src/host/layer23/src/common/l1ctl.c | 36 | ||||
-rw-r--r-- | src/host/layer23/src/common/sim.c (renamed from src/host/layer23/src/mobile/sim.c) | 126 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/Makefile.am | 2 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/app_mobile.c | 21 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm322.c | 6 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/subscriber.c | 32 |
11 files changed, 161 insertions, 73 deletions
diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h index d76614b2..80687a1a 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 01a49b20..189df898 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 d9538282..7ffbfd93 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 <osmocom/bb/mobile/gsm322.h> #include <osmocom/bb/mobile/gsm48_mm.h> #include <osmocom/bb/mobile/gsm48_cc.h> -#include <osmocom/bb/mobile/sim.h> +#include <osmocom/bb/common/sim.h> /* 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 index be8b8b57..c1e6087a 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 1dadb513..b9019bbc 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 abf4f8e0..72ccd5f7 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 index d4d1821f..543292ee 100644 --- a/src/host/layer23/src/mobile/sim.c +++ b/src/host/layer23/src/common/sim.c @@ -27,6 +27,7 @@ #include <osmocom/bb/common/logging.h> #include <osmocom/bb/common/osmocom_data.h> +#include <osmocom/bb/common/l1ctl.h> 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 b5d910a7..055b3c2a 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 154768b2..80cd26b1 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 fbeff2ab..fb8b85bd 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 fce62f0d..b95858f8 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 */ |