diff options
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/settings.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/subscriber.h | 41 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/app_mobile.c | 31 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm322.c | 10 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_mm.c | 216 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_rr.c | 46 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/subscriber.c | 830 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/vty_interface.c | 67 |
9 files changed, 1033 insertions, 212 deletions
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h index 68c00d45..e8b44dc7 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h +++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h @@ -187,6 +187,8 @@ struct msgb *gsm48_l3_msgb_alloc(void); struct msgb *gsm48_rr_msgb_alloc(int msg_type); int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, uint16_t *mnc, uint16_t *lac); +int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc, + uint16_t mnc, uint16_t lac); int gsm48_rr_enc_cm2(struct osmocom_ms *ms, struct gsm48_classmark2 *cm); int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg); int gsm48_rr_los(struct osmocom_ms *ms); diff --git a/src/host/layer23/include/osmocom/bb/mobile/settings.h b/src/host/layer23/include/osmocom/bb/mobile/settings.h index be13d208..2dc62202 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/settings.h +++ b/src/host/layer23/include/osmocom/bb/mobile/settings.h @@ -11,7 +11,7 @@ struct gsm_settings { int plmn_mode; /* PLMN_MODE_* */ /* SIM */ - int simtype; /* selects card on power on */ + int sim_type; /* selects card on power on */ char emergency_imsi[20]; /* just in case... */ /* test card simulator settings */ diff --git a/src/host/layer23/include/osmocom/bb/mobile/subscriber.h b/src/host/layer23/include/osmocom/bb/mobile/subscriber.h index 34f45289..cf0e5acf 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/subscriber.h +++ b/src/host/layer23/include/osmocom/bb/mobile/subscriber.h @@ -22,32 +22,37 @@ struct gsm_sub_plmn_na { enum { GSM_SIM_TYPE_NONE = 0, - GSM_SIM_TYPE_SLOT, + GSM_SIM_TYPE_READER, GSM_SIM_TYPE_TEST }; +/* state of reading SIM */ +enum { + SUBSCR_SIM_NULL = 0, +}; + struct gsm_subscriber { struct osmocom_ms *ms; /* status */ + uint8_t sim_type; /* type of sim */ uint8_t sim_valid; /* sim inserted and valid */ uint8_t ustate; /* update status */ uint8_t imsi_attached; /* attached state */ - /* LAI */ - uint8_t lai_valid; - uint16_t lai_mcc, lai_mnc, lai_lac; - - /* IMSI */ + /* IMSI & co */ char imsi[GSM_IMSI_LENGTH]; + char msisdn[31]; /* may include access codes */ + char iccid[21]; /* 20 + termination */ + + /* TMSI / LAI */ + uint32_t tmsi; /* invalid tmsi: 0xffffffff */ + uint16_t mcc, mnc, lac; /* invalid lac: 0x0000 */ - /* TMSI */ - uint8_t tmsi_valid; - uint32_t tmsi; /* key */ uint8_t key_seq; /* ciphering key sequence number */ - uint8_t key[32]; /* up to 256 bit */ + uint8_t key[64]; /* 64 bit */ /* other */ struct llist_head plmn_list; /* PLMN Selector field */ @@ -57,7 +62,8 @@ struct gsm_subscriber { /* special things */ uint8_t always_search_hplmn; /* search hplmn in other countries also (for test cards) */ - char sim_name[32]; /* name to load/save sim */ + char sim_name[31]; /* name to load/save sim */ + char sim_spn[17]; /* name of service privider */ /* PLMN last registered */ uint8_t plmn_valid; @@ -66,11 +72,24 @@ struct gsm_subscriber { /* our access */ uint8_t acc_barr; /* if we may access, if cell barred */ uint16_t acc_class; /* bitmask of what we may access */ + + /* talk to SIM */ + uint8_t sim_state; + uint8_t sim_pin_required; /* state: wait for PIN */ + uint8_t sim_file_index; + uint32_t sim_handle_query; + uint32_t sim_handle_update; + uint32_t sim_handle_key; }; int gsm_subscr_init(struct osmocom_ms *ms); int gsm_subscr_exit(struct osmocom_ms *ms); int gsm_subscr_testcard(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc); +int gsm_subscr_simcard(struct osmocom_ms *ms); +void gsm_subscr_sim_pin(struct osmocom_ms *ms, char *pin); +int gsm_subscr_write_loci(struct osmocom_ms *ms); +int gsm_subscr_generate_kc(struct osmocom_ms *ms, uint8_t key_seq, + uint8_t *rand); int gsm_subscr_remove(struct osmocom_ms *ms); void new_sim_ustate(struct gsm_subscriber *subscr, int state); int gsm_subscr_del_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc, diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c index 9a98f89f..154768b2 100644 --- a/src/host/layer23/src/mobile/app_mobile.c +++ b/src/host/layer23/src/mobile/app_mobile.c @@ -47,7 +47,7 @@ static const char *config_file = "/etc/osmocom/osmocom.cfg"; extern void *l23_ctx; extern unsigned short vty_port; -static int started = 0; +int mobile_started = 0; int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg); @@ -64,6 +64,7 @@ int mobile_work(struct osmocom_ms *ms) w |= gsm48_mmevent_dequeue(ms); w |= gsm322_plmn_dequeue(ms); w |= gsm322_cs_dequeue(ms); + w |= gsm_sim_job_dequeue(ms); w |= mncc_dequeue(ms); if (w) work = 1; @@ -83,15 +84,27 @@ static int signal_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_L1CTL_RESET: - if (started) + if (mobile_started) break; - started = 1; + ms = signal_data; set = &ms->settings; + /* insert test card, if enabled */ - if (set->simtype == GSM_SIM_TYPE_TEST) + switch (set->sim_type) { + case GSM_SIM_TYPE_READER: + /* trigger sim card reader process */ + gsm_subscr_simcard(ms); + break; + case GSM_SIM_TYPE_TEST: gsm_subscr_testcard(ms, set->test_rplmn_mcc, set->test_rplmn_mnc); + break; + default: + /* no SIM */ + ; + } + /* start PLMN + cell selection process */ nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON); if (!nmsg) @@ -101,6 +114,8 @@ static int signal_cb(unsigned int subsys, unsigned int signal, if (!nmsg) return -ENOMEM; gsm322_cs_sendmsg(ms, nmsg); + + mobile_started = 1; } return 0; } @@ -109,7 +124,7 @@ int mobile_exit(struct osmocom_ms *ms) { struct gsm48_mmlayer *mm = &ms->mmlayer; - if (!mm->power_off && started) { + if (!mm->power_off && mobile_started) { struct msgb *nmsg; mm->power_off = 1; @@ -134,6 +149,7 @@ int mobile_exit(struct osmocom_ms *ms) gsm48_rr_exit(ms); gsm_subscr_exit(ms); gsm48_cc_exit(ms); + gsm_sim_exit(ms); printf("Power off!\n"); @@ -151,11 +167,12 @@ int l23_app_init(struct osmocom_ms *ms) int rc; struct telnet_connection dummy_conn; -// log_parse_category_mask(stderr_target, "DRSL:DLAPDM:DCS:DPLMN:DRR:DMM:DCC:DMNCC:DPAG:DSUM"); - log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DCC:DMNCC:DPAG:DSUM"); +// log_parse_category_mask(stderr_target, "DRSL:DLAPDM:DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM"); + log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM"); srand(time(NULL)); + gsm_sim_init(ms); gsm_settings_init(ms); gsm48_cc_init(ms); gsm_support_init(ms); diff --git a/src/host/layer23/src/mobile/gsm322.c b/src/host/layer23/src/mobile/gsm322.c index 9098f24c..fbeff2ab 100644 --- a/src/host/layer23/src/mobile/gsm322.c +++ b/src/host/layer23/src/mobile/gsm322.c @@ -748,12 +748,10 @@ static int gsm322_a_go_on_plmn(struct osmocom_ms *ms, struct msgb *msg) /* start timer, if on VPLMN of home country OR special case */ if (!gsm_match_mnc(plmn->mcc, plmn->mnc, subscr->imsi) && (subscr->always_search_hplmn - || gsm_match_mcc(plmn->mcc, subscr->imsi))) { - if (subscr->sim_valid && subscr->t6m_hplmn) - start_plmn_timer(plmn, subscr->t6m_hplmn * 360); - else - start_plmn_timer(plmn, 30 * 360); - } else + || gsm_match_mcc(plmn->mcc, subscr->imsi)) + && subscr->sim_valid && subscr->t6m_hplmn) + start_plmn_timer(plmn, subscr->t6m_hplmn * 360); + else stop_plmn_timer(plmn); return 0; diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c index 8228a1c1..7abc77e4 100644 --- a/src/host/layer23/src/mobile/gsm48_mm.c +++ b/src/host/layer23/src/mobile/gsm48_mm.c @@ -978,7 +978,7 @@ static int gsm48_mm_set_plmn_search(struct osmocom_ms *ms) "SIM not updated.\n"); return GSM48_MM_SST_PLMN_SEARCH; } - if (!subscr->lai_valid) { + if (subscr->lac == 0x0000 || subscr->lac >= 0xfffe) { LOGP(DMM, LOGL_INFO, "Selecting PLMN SEARCH state, because " "LAI in SIM not valid.\n"); return GSM48_MM_SST_PLMN_SEARCH; @@ -992,15 +992,15 @@ static int gsm48_mm_set_plmn_search(struct osmocom_ms *ms) } /* selected cell's LAI not equal to LAI stored on the sim */ - if (cs->sel_mcc != subscr->lai_mcc - || cs->sel_mnc != subscr->lai_mnc - || cs->sel_lac != subscr->lai_lac) { + if (cs->sel_mcc != subscr->mcc + || cs->sel_mnc != subscr->mnc + || cs->sel_lac != subscr->lac) { LOGP(DMM, LOGL_INFO, "Selecting PLMN SEARCH state, because " "LAI of selected cell (MCC %s MNC %s LAC 0x%04x) " "!= LAI in SIM (MCC %s MNC %s LAC 0x%04x).\n", gsm_print_mcc(cs->sel_mcc), gsm_print_mnc(cs->sel_mnc), - cs->sel_lac, gsm_print_mcc(subscr->lai_mcc), - gsm_print_mnc(subscr->lai_mnc), subscr->lai_lac); + cs->sel_lac, gsm_print_mcc(subscr->mcc), + gsm_print_mnc(subscr->mnc), subscr->lac); return GSM48_MM_SST_PLMN_SEARCH; } @@ -1047,10 +1047,10 @@ static int gsm48_mm_return_idle(struct osmocom_ms *ms, struct msgb *msg) } /* selected cell equals the registered LAI */ - if (subscr->lai_valid - && cs->sel_mcc == subscr->lai_mcc - && cs->sel_mnc == subscr->lai_mnc - && cs->sel_lac == subscr->lai_lac) { + if (subscr->lac /* valid */ + && cs->sel_mcc == subscr->mcc + && cs->sel_mnc == subscr->mnc + && cs->sel_lac == subscr->lac) { LOGP(DMM, LOGL_INFO, "We are in registered LAI as returning " "to MM IDLE\n"); /* if SIM not updated (abnormal case as described in 4.4.4.9) */ @@ -1112,10 +1112,10 @@ static int gsm48_mm_cell_selected(struct osmocom_ms *ms, struct msgb *msg) /* SIM not updated in this LA */ if (subscr->ustate == GSM_SIM_U1_UPDATED - && subscr->lai_valid - && cs->sel_mcc == subscr->lai_mcc - && cs->sel_mnc == subscr->lai_mnc - && cs->sel_lac == subscr->lai_lac + && subscr->lac /* valid */ + && cs->sel_mcc == subscr->mcc + && cs->sel_mnc == subscr->mnc + && cs->sel_lac == subscr->lac && !mm->lupd_periodic) { if (subscr->imsi_attached) { struct msgb *nmsg; @@ -1473,8 +1473,7 @@ static int gsm48_mm_rx_tmsi_realloc_cmd(struct osmocom_ms *ms, struct msgb *msg) return -EINVAL; } /* LAI */ - gsm48_decode_lai(lai, &subscr->lai_mcc, &subscr->lai_mnc, - &subscr->lai_lac); + gsm48_decode_lai(lai, &subscr->mcc, &subscr->mnc, &subscr->lac); /* MI */ mi = gh->data + sizeof(struct gsm48_loc_area_id); mi_type = mi[1] & GSM_MI_TYPE_MASK; @@ -1485,35 +1484,28 @@ static int gsm48_mm_rx_tmsi_realloc_cmd(struct osmocom_ms *ms, struct msgb *msg) goto short_read; memcpy(&tmsi, mi+2, 4); subscr->tmsi = ntohl(tmsi); - subscr->tmsi_valid = 1; LOGP(DMM, LOGL_INFO, "TMSI 0x%08x (%u) assigned.\n", subscr->tmsi, subscr->tmsi); gsm48_mm_tx_tmsi_reall_cpl(ms); break; case GSM_MI_TYPE_IMSI: - subscr->tmsi_valid = 0; + subscr->tmsi = 0x00000000; LOGP(DMM, LOGL_INFO, "TMSI removed.\n"); gsm48_mm_tx_tmsi_reall_cpl(ms); break; default: + subscr->tmsi = 0x00000000; LOGP(DMM, LOGL_NOTICE, "TMSI reallocation with unknown MI " "type %d.\n", mi_type); gsm48_mm_tx_mm_status(ms, GSM48_REJECT_INCORRECT_MESSAGE); - - return 0; /* don't store in SIM */ } -#ifdef TODO - store / remove from sim -#endif + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); return 0; } -#ifndef TODO -static int gsm48_mm_tx_auth_rsp(struct osmocom_ms *ms, struct msgb *msg); -#endif - /* 4.3.2.2 AUTHENTICATION REQUEST is received */ static int gsm48_mm_rx_auth_req(struct osmocom_ms *ms, struct msgb *msg) { @@ -1537,22 +1529,10 @@ static int gsm48_mm_rx_auth_req(struct osmocom_ms *ms, struct msgb *msg) LOGP(DMM, LOGL_INFO, "AUTHENTICATION REQUEST (seq %d)\n", ar->key_seq); - /* key_seq and random */ -#ifdef TODO - new key to sim: - (..., ar->key_seq, ar->rand); -#else - /* Fake response */ - struct msgb *nmsg; - struct gsm48_mm_event *nmme; - nmsg = gsm48_l3_msgb_alloc(); - if (!nmsg) - return -ENOMEM; - nmme = (struct gsm48_mm_event *)msgb_put(nmsg, sizeof(*nmme)); - *((uint32_t *)nmme->sres) = 0x12345678; - gsm48_mm_tx_auth_rsp(ms, nmsg); - msgb_free(nmsg); -#endif + /* key_seq and random + * in case of test case, there is a fake response + */ + gsm_subscr_generate_kc(ms, ar->key_seq, ar->rand); /* wait for auth response event from SIM */ return 0; @@ -1598,8 +1578,8 @@ static int gsm48_mm_rx_auth_rej(struct osmocom_ms *ms, struct msgb *msg) subscr->sim_valid = 0; /* TMSI and LAI invalid */ - subscr->lai_valid = 0; - subscr->tmsi_valid = 0; + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; /* key is invalid */ subscr->key_seq = 7; @@ -1607,11 +1587,8 @@ static int gsm48_mm_rx_auth_rej(struct osmocom_ms *ms, struct msgb *msg) /* update status */ new_sim_ustate(subscr, GSM_SIM_U3_ROAMING_NA); -#ifdef TODO - sim: delete tmsi, lai - sim: delete key seq number - sim: set update status -#endif + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); /* abort IMSI detach procedure */ if (mm->state == GSM48_MM_ST_IMSI_DETACH_INIT) { @@ -1658,7 +1635,7 @@ static int gsm48_mm_rx_id_req(struct osmocom_ms *ms, struct msgb *msg) return gsm48_mm_tx_mm_status(ms, GSM48_REJECT_MSG_NOT_COMPATIBLE); } - if (mi_type == GSM_MI_TYPE_TMSI && !subscr->tmsi_valid) { + if (mi_type == GSM_MI_TYPE_TMSI && subscr->tmsi == 0xffffffff) { LOGP(DMM, LOGL_INFO, "IDENTITY REQUEST of TMSI, but we have no " "TMSI\n"); return gsm48_mm_tx_mm_status(ms, @@ -1724,7 +1701,7 @@ static int gsm48_mm_tx_imsi_detach(struct osmocom_ms *ms, int rr_prim) pwr_lev); msgb_v_put(nmsg, *((uint8_t *)&cm)); /* MI */ - if (subscr->tmsi_valid) /* have TMSI ? */ + if (subscr->tmsi != 0xffffffff) /* have TMSI ? */ gsm48_encode_mi(buf, nmsg, ms, GSM_MI_TYPE_TMSI); else gsm48_encode_mi(buf, nmsg, ms, GSM_MI_TYPE_IMSI); @@ -1745,11 +1722,6 @@ static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, struct msgb *msg) /* stop IMSI detach timer (if running) */ stop_mm_t3220(mm); - /* update SIM */ -#ifdef TODO - sim: store BA list - sim: what else?: -#endif /* SIM invalid */ subscr->sim_valid = 0; @@ -1899,8 +1871,8 @@ static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg) subscr->sim_valid = 0; /* TMSI and LAI invalid */ - subscr->lai_valid = 0; - subscr->tmsi_valid = 0; + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; /* key is invalid */ subscr->key_seq = 7; @@ -1908,11 +1880,8 @@ static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg) /* update status */ new_sim_ustate(subscr, GSM_SIM_U3_ROAMING_NA); -#ifdef TODO - sim: delete tmsi, lai - sim: delete key seq number - sim: apply update state -#endif + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); /* CS process will trigger: return to MM IDLE / No SIM */ return 0; @@ -2029,7 +1998,8 @@ static int gsm48_mm_loc_upd(struct osmocom_ms *ms, struct msgb *msg) LOGP(DMM, LOGL_INFO, "Loc. upd. not camping normally.\n"); msg_type = GSM322_EVENT_REG_FAILED; stop: - LOGP(DSUM, LOGL_INFO, "Location update not possible\n"); + LOGP(DSUM, LOGL_INFO, "Location updating not possible\n"); + _stop: mm->lupd_pending = 0; /* send message to PLMN search process */ nmsg = gsm322_msgb_alloc(msg_type); @@ -2043,10 +2013,12 @@ static int gsm48_mm_loc_upd(struct osmocom_ms *ms, struct msgb *msg) if (set->no_lupd) { LOGP(DMM, LOGL_INFO, "Loc. upd. disabled, adding " "forbidden PLMN.\n"); + LOGP(DSUM, LOGL_INFO, "Location updating is disabled by " + "configuration\n"); gsm_subscr_add_forbidden_plmn(subscr, cs->sel_mcc, cs->sel_mnc, GSM48_REJECT_PLMN_NOT_ALLOWED); msg_type = GSM322_EVENT_ROAMING_NA; - goto stop; + goto _stop; } /* if LAI is forbidden, don't start */ @@ -2114,9 +2086,9 @@ static int gsm48_mm_loc_upd_normal(struct osmocom_ms *ms, struct msgb *msg) /* if location update is not required */ if (subscr->ustate == GSM_SIM_U1_UPDATED && cs->selected - && cs->sel_mcc == subscr->lai_mcc - && cs->sel_mnc == subscr->lai_mnc - && cs->sel_lac == subscr->lai_lac + && cs->sel_mcc == subscr->mcc + && cs->sel_mnc == subscr->mnc + && cs->sel_lac == subscr->lac && (subscr->imsi_attached || !s->att_allowed)) { LOGP(DMM, LOGL_INFO, "Loc. upd. not required.\n"); @@ -2134,9 +2106,9 @@ static int gsm48_mm_loc_upd_normal(struct osmocom_ms *ms, struct msgb *msg) /* 4.4.3 is attachment required? */ if (subscr->ustate == GSM_SIM_U1_UPDATED && cs->selected - && cs->sel_mcc == subscr->lai_mcc - && cs->sel_mnc == subscr->lai_mnc - && cs->sel_lac == subscr->lai_lac + && cs->sel_mcc == subscr->mcc + && cs->sel_mnc == subscr->mnc + && cs->sel_lac == subscr->lac && !subscr->imsi_attached && s->att_allowed) { /* do location update for IMSI attach */ @@ -2209,9 +2181,11 @@ static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms) nlu->type = mm->lupd_type; /* cipering key */ nlu->key_seq = subscr->key_seq; - /* LAI (use last SIM stored LAI) */ - gsm48_generate_lai(&nlu->lai, - subscr->lai_mcc, subscr->lai_mnc, subscr->lai_lac); + /* LAI (last SIM stored LAI) + * + * NOTE: The TMSI is only valid within a LAI! + */ + gsm48_encode_lai(&nlu->lai, subscr->mcc, subscr->mnc, subscr->lac); /* classmark 1 */ if (rr->cd_now.arfcn >= 512 && rr->cd_now.arfcn <= 885) pwr_lev = sup->pwr_lev_1800; @@ -2220,7 +2194,7 @@ static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms) gsm48_encode_classmark1(&nlu->classmark1, sup->rev_lev, sup->es_ind, sup->a5_1, pwr_lev); /* MI */ - if (subscr->tmsi_valid) /* have TMSI ? */ + if (subscr->tmsi != 0xffffffff) /* have TMSI ? */ gsm48_encode_mi(buf, NULL, ms, GSM_MI_TYPE_TMSI); else gsm48_encode_mi(buf, NULL, ms, GSM_MI_TYPE_IMSI); @@ -2277,9 +2251,7 @@ static int gsm48_mm_rx_loc_upd_acc(struct osmocom_ms *ms, struct msgb *msg) stop_mm_t3212(mm); /* 4.4.2 */ /* LAI */ - subscr->lai_valid = 1; - gsm48_decode_lai(lai, &subscr->lai_mcc, &subscr->lai_mnc, - &subscr->lai_lac); + gsm48_decode_lai(lai, &subscr->mcc, &subscr->mnc, &subscr->lac); /* stop location update timer */ stop_mm_t3210(mm); @@ -2292,26 +2264,24 @@ static int gsm48_mm_rx_loc_upd_acc(struct osmocom_ms *ms, struct msgb *msg) /* set the status in the sim to updated */ new_sim_ustate(subscr, GSM_SIM_U1_UPDATED); -#ifdef TODO - sim: apply update state -#endif + + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); /* set last registered PLMN */ - subscr->plmn_valid = 1; - subscr->plmn_mcc = subscr->lai_mcc; - subscr->plmn_mnc = subscr->lai_mnc; -#ifdef TODO - sim: store plmn -#endif + if (subscr->lac > 0x0000 && subscr->lac < 0xfffe) { + subscr->plmn_valid = 1; + subscr->plmn_mcc = subscr->mcc; + subscr->plmn_mnc = subscr->mnc; + } LOGP(DSUM, LOGL_INFO, "Location update accepted\n"); LOGP(DMM, LOGL_INFO, "LOCATION UPDATING ACCEPT (mcc %s mnc %s " - "lac 0x%04x)\n", gsm_print_mcc(subscr->lai_mcc), - gsm_print_mnc(subscr->lai_mnc), subscr->lai_lac); + "lac 0x%04x)\n", gsm_print_mcc(subscr->mcc), + gsm_print_mnc(subscr->mnc), subscr->lac); /* remove LA from forbidden list */ - gsm322_del_forbidden_la(ms, subscr->lai_mcc, subscr->lai_mnc, - subscr->lai_lac); + gsm322_del_forbidden_la(ms, subscr->mcc, subscr->mnc, subscr->lac); /* MI */ if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) { @@ -2330,19 +2300,20 @@ static int gsm48_mm_rx_loc_upd_acc(struct osmocom_ms *ms, struct msgb *msg) goto short_read; memcpy(&tmsi, mi+2, 4); subscr->tmsi = ntohl(tmsi); - subscr->tmsi_valid = 1; LOGP(DMM, LOGL_INFO, "got TMSI 0x%08x (%u)\n", subscr->tmsi, subscr->tmsi); -#ifdef TODO - sim: store tmsi -#endif + + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); + break; case GSM_MI_TYPE_IMSI: LOGP(DMM, LOGL_INFO, "TMSI removed\n"); - subscr->tmsi_valid = 0; -#ifdef TODO - sim: delete tmsi -#endif + subscr->tmsi = 0xffffffff; + + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); + /* send TMSI REALLOCATION COMPLETE */ gsm48_mm_tx_tmsi_reall_cpl(ms); break; @@ -2433,19 +2404,18 @@ static int gsm48_mm_rel_loc_upd_rej(struct osmocom_ms *ms, struct msgb *msg) case GSM48_REJECT_LOC_NOT_ALLOWED: case GSM48_REJECT_ROAMING_NOT_ALLOWED: /* TMSI and LAI invalid */ - subscr->lai_valid = 0; - subscr->tmsi_valid = 0; + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; /* key is invalid */ subscr->key_seq = 7; /* update status */ new_sim_ustate(subscr, GSM_SIM_U3_ROAMING_NA); -#ifdef TODO - sim: delete tmsi, lai - sim: delete key seq number - sim: apply update state -#endif + + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); + /* update has finished */ mm->lupd_pending = 0; } @@ -2537,9 +2507,9 @@ static int gsm48_mm_loc_upd_failed(struct osmocom_ms *ms, struct msgb *msg) stop_mm_t3210(mm); if (subscr->ustate == GSM_SIM_U1_UPDATED - && mm->lupd_mcc == subscr->lai_mcc - && mm->lupd_mnc == subscr->lai_mnc - && mm->lupd_lac == subscr->lai_lac) { + && mm->lupd_mcc == subscr->mcc + && mm->lupd_mnc == subscr->mnc + && mm->lupd_lac == subscr->lac) { if (mm->lupd_attempt < 4) { LOGP(DSUM, LOGL_INFO, "Try location update later\n"); LOGP(DMM, LOGL_INFO, "Loc. upd. failed, retry #%d\n", @@ -2555,8 +2525,8 @@ static int gsm48_mm_loc_upd_failed(struct osmocom_ms *ms, struct msgb *msg) } /* TMSI and LAI invalid */ - subscr->lai_valid = 0; - subscr->tmsi_valid = 0; + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; /* key is invalid */ subscr->key_seq = 7; @@ -2564,11 +2534,8 @@ static int gsm48_mm_loc_upd_failed(struct osmocom_ms *ms, struct msgb *msg) /* update status */ new_sim_ustate(subscr, GSM_SIM_U2_NOT_UPDATED); -#ifdef TODO - sim: delete tmsi, lai - sim: delete key seq number - sim: set update status -#endif + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); /* start update retry timer (RR connection is released) */ if (mm->lupd_attempt < 4) { @@ -2679,7 +2646,7 @@ static int gsm48_mm_tx_cm_serv_req(struct osmocom_ms *ms, int rr_prim, set->imei); gsm48_encode_mi(buf, NULL, ms, GSM_MI_TYPE_IMEI); } else - if (subscr->tmsi_valid) { /* have TMSI ? */ + if (subscr->tmsi != 0xffffffff) { /* have TMSI ? */ gsm48_encode_mi(buf, NULL, ms, GSM_MI_TYPE_TMSI); LOGP(DMM, LOGL_INFO, "-> Using TMSI\n"); } else { @@ -2761,8 +2728,8 @@ static int gsm48_mm_rx_cm_service_rej(struct osmocom_ms *ms, struct msgb *msg) abort_any = 1; /* TMSI and LAI invalid */ - subscr->lai_valid = 0; - subscr->tmsi_valid = 0; + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; /* key is invalid */ subscr->key_seq = 7; @@ -2770,11 +2737,8 @@ static int gsm48_mm_rx_cm_service_rej(struct osmocom_ms *ms, struct msgb *msg) /* update status */ new_sim_ustate(subscr, GSM_SIM_U2_NOT_UPDATED); -#ifdef TODO - sim: delete tmsi, lai - sim: delete key seq number - sim: set update status -#endif + /* store LOCI on sim */ + gsm_subscr_write_loci(ms); /* change to WAIT_NETWORK_CMD state impied by abort_any == 1 */ @@ -4122,7 +4086,7 @@ static int gsm48_mmr_nreg_req(struct osmocom_ms *ms) struct gsm48_mmlayer *mm = &ms->mmlayer; struct msgb *nmsg; - nmsg = gsm322_msgb_alloc(GSM48_MM_EVENT_IMSI_DETACH); + nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_IMSI_DETACH); if (!nmsg) return -ENOMEM; gsm48_mmevent_msg(mm->ms, nmsg); diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c index 5c39d778..16972a85 100644 --- a/src/host/layer23/src/mobile/gsm48_rr.c +++ b/src/host/layer23/src/mobile/gsm48_rr.c @@ -106,6 +106,17 @@ int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, return 0; } +int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc, + uint16_t mnc, uint16_t lac) +{ + lai->digits[0] = (mcc >> 8) | (mcc & 0xf0); + lai->digits[1] = (mcc & 0x0f) | (mnc << 4); + lai->digits[2] = (mnc >> 8) | (mnc & 0xf0); + lai->lac = htons(lac); + + return 0; +} + static int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc, uint16_t *arfcn) { @@ -2156,6 +2167,7 @@ static int gsm48_rr_chan2cause[4] = { /* given LV of mobile identity is checked agains ms */ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi) { + struct gsm322_cellsel *cs = &ms->cellsel; char imsi[16]; uint32_t tmsi; uint8_t mi_type; @@ -2169,7 +2181,9 @@ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi) return 0; memcpy(&tmsi, mi+2, 4); if (ms->subscr.tmsi == ntohl(tmsi) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(tmsi)); @@ -2284,7 +2298,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg) chan_2 = pa->cneed2; /* first MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi1) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1); } else @@ -2292,7 +2308,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi1)); /* second MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi2) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1); } else @@ -2346,7 +2364,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) chan_4 = pa->cneed4; /* first MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi1) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1); } else @@ -2354,7 +2374,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi1)); /* second MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi2) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1); } else @@ -2362,7 +2384,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi2)); /* thrid MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi3) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi3)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1); } else @@ -2370,7 +2394,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi3)); /* fourth MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi4) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi4)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1); } else @@ -3033,6 +3059,7 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd, static int gsm48_rr_dl_est(struct osmocom_ms *ms) { struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm322_cellsel *cs = &ms->cellsel; struct gsm_subscriber *subscr = &ms->subscr; struct msgb *nmsg; struct gsm48_hdr *gh; @@ -3111,7 +3138,10 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms) pr->cm2_len = sizeof(pr->cm2); gsm48_rr_enc_cm2(ms, &pr->cm2); /* mobile identity */ - if (ms->subscr.tmsi_valid) { + if (ms->subscr.tmsi != 0xffffffff + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { gsm48_generate_mid_from_tmsi(mi, subscr->tmsi); LOGP(DRR, LOGL_INFO, "sending paging response with " "TMSI\n"); diff --git a/src/host/layer23/src/mobile/subscriber.c b/src/host/layer23/src/mobile/subscriber.c index 44434901..a316c8e7 100644 --- a/src/host/layer23/src/mobile/subscriber.c +++ b/src/host/layer23/src/mobile/subscriber.c @@ -22,14 +22,64 @@ #include <stdint.h> #include <errno.h> #include <string.h> +#include <arpa/inet.h> #include <osmocore/talloc.h> #include <osmocom/bb/common/logging.h> #include <osmocom/bb/common/osmocom_data.h> #include <osmocom/bb/common/networks.h> +#include <osmocom/bb/mobile/vty.h> void *l23_ctx; +static void subscr_sim_query_cb(struct osmocom_ms *ms, struct msgb *msg); +static void subscr_sim_update_cb(struct osmocom_ms *ms, struct msgb *msg); +static void subscr_sim_key_cb(struct osmocom_ms *ms, struct msgb *msg); + +/* + * support + */ + +char *gsm_check_imsi(const char *imsi) +{ + int i; + + if (!imsi || strlen(imsi) != 15) + return "IMSI must have 15 digits!"; + + for (i = 0; i < strlen(imsi); i++) { + if (imsi[i] < '0' || imsi[i] > '9') + return "IMSI must have digits 0 to 9 only!"; + } + + return NULL; +} + +static char *sim_decode_bcd(uint8_t *data, uint8_t length) +{ + int i, j = 0; + static char result[32], c; + + for (i = 0; i < (length << 1); i++) { + if ((i & 1)) + c = (data[i >> 1] >> 4) + '0'; + else + c = (data[i >> 1] & 0xf) + '0'; + if (c == 0xf) + break; + result[j++] = c; + if (j == sizeof(result) - 1) + break; + } + result[j] = '\0'; + + return result; +} + +/* + * init/exit + */ + int gsm_subscr_init(struct osmocom_ms *ms) { struct gsm_subscriber *subscr = &ms->subscr; @@ -37,6 +87,10 @@ int gsm_subscr_init(struct osmocom_ms *ms) memset(subscr, 0, sizeof(*subscr)); subscr->ms = ms; + /* set TMSI / LAC invalid */ + subscr->tmsi = 0xffffffff; + subscr->lac = 0x0000; + /* set key invalid */ subscr->key_seq = 7; @@ -44,6 +98,12 @@ int gsm_subscr_init(struct osmocom_ms *ms) INIT_LLIST_HEAD(&subscr->plmn_list); INIT_LLIST_HEAD(&subscr->plmn_na); + /* open SIM */ + subscr->sim_handle_query = sim_open(ms, subscr_sim_query_cb); + subscr->sim_handle_update = sim_open(ms, subscr_sim_update_cb); + subscr->sim_handle_key = sim_open(ms, subscr_sim_key_cb); + subscr->sim_state = SUBSCR_SIM_NULL; + return 0; } @@ -52,6 +112,19 @@ int gsm_subscr_exit(struct osmocom_ms *ms) struct gsm_subscriber *subscr = &ms->subscr; struct llist_head *lh, *lh2; + if (subscr->sim_handle_query) { + sim_close(ms, subscr->sim_handle_query); + subscr->sim_handle_query = 0; + } + if (subscr->sim_handle_update) { + sim_close(ms, subscr->sim_handle_update); + subscr->sim_handle_update = 0; + } + if (subscr->sim_handle_key) { + sim_close(ms, subscr->sim_handle_key); + subscr->sim_handle_key = 0; + } + /* flush lists */ llist_for_each_safe(lh, lh2, &subscr->plmn_list) { llist_del(lh); @@ -65,12 +138,16 @@ int gsm_subscr_exit(struct osmocom_ms *ms) return 0; } -/* Attach test card, no sim must be present */ +/* + * test card + */ + +/* Attach test card, no SIM must be currently attached */ int gsm_subscr_testcard(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc) { struct gsm_settings *set = &ms->settings; struct gsm_subscriber *subscr = &ms->subscr; - struct msgb *msg; + struct msgb *nmsg; char *error; if (subscr->sim_valid) { @@ -89,8 +166,8 @@ int gsm_subscr_testcard(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc) gsm_subscr_exit(ms); gsm_subscr_init(ms); + subscr->sim_type = GSM_SIM_TYPE_TEST; sprintf(subscr->sim_name, "test"); - // TODO: load / save SIM to file system subscr->sim_valid = 1; subscr->ustate = GSM_SIM_U2_NOT_UPDATED; subscr->acc_barr = set->test_barr; /* we may access barred cell */ @@ -106,24 +183,702 @@ int gsm_subscr_testcard(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc) ms->name, subscr->imsi, gsm_imsi_mcc(subscr->imsi), gsm_imsi_mnc(subscr->imsi)); - LOGP(DMM, LOGL_INFO, "-> Test card regisered to %s %s (%s, %s)\n", - gsm_print_mcc(mcc), gsm_print_mnc(mnc), gsm_get_mcc(mcc), - gsm_get_mnc(mcc, mnc)); + if (subscr->plmn_valid) + LOGP(DMM, LOGL_INFO, "-> Test card registered to %s %s " + "(%s, %s)\n", gsm_print_mcc(mcc), gsm_print_mnc(mnc), + gsm_get_mcc(mcc), gsm_get_mnc(mcc, mnc)); + else + LOGP(DMM, LOGL_INFO, "-> Test card not registered\n"); /* insert card */ - msg = gsm48_mmr_msgb_alloc(GSM48_MMR_REG_REQ); - if (!msg) + nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_REG_REQ); + if (!nmsg) return -ENOMEM; - gsm48_mmr_downmsg(ms, msg); + gsm48_mmr_downmsg(ms, nmsg); + + return 0; +} + +/* + * sim card + */ + +static int subscr_sim_iccid(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + + strcpy(subscr->iccid, sim_decode_bcd(data, length)); + sprintf(subscr->sim_name, "sim-%s", subscr->iccid); + LOGP(DMM, LOGL_INFO, "received ICCID %s from SIM\n", subscr->iccid); + + return 0; +} + +static int subscr_sim_imsi(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + + /* get actual length */ + if (length < 1) + return -EINVAL; + if (data[0] + 1 < length) { + LOGP(DMM, LOGL_NOTICE, "invalid length = %d\n", length); + return -EINVAL; + } + length = data[0]; + if ((length << 1) > GSM_IMSI_LENGTH - 1 || (length << 1) < 6) { + LOGP(DMM, LOGL_NOTICE, "IMSI invalid length = %d\n", + length << 1); + return -EINVAL; + } + + strncpy(subscr->imsi, sim_decode_bcd(data + 1, length), + sizeof(subscr->imsi - 1)); + + LOGP(DMM, LOGL_INFO, "received IMSI %s from SIM\n", subscr->imsi); + + return 0; +} + +static int subscr_sim_loci(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct gsm1111_ef_loci *loci; + + if (length < 11) + return -EINVAL; + loci = (struct gsm1111_ef_loci *) data; + + /* TMSI */ + subscr->tmsi = ntohl(loci->tmsi); + + /* LAI */ + gsm48_decode_lai(&loci->lai, &subscr->mcc, &subscr->mnc, &subscr->lac); + + /* location update status */ + switch (loci->lupd_status & 0x07) { + case 0x00: + subscr->ustate = GSM_SIM_U1_UPDATED; + break; + case 0x02: + case 0x03: + subscr->ustate = GSM_SIM_U3_ROAMING_NA; + break; + default: + subscr->ustate = GSM_SIM_U2_NOT_UPDATED; + } + + LOGP(DMM, LOGL_INFO, "received LOCI from SIM\n"); return 0; } +static int subscr_sim_msisdn(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct gsm1111_ef_adn *adn; + + if (length < sizeof(*adn)) + return -EINVAL; + adn = (struct gsm1111_ef_adn *) (data + length - sizeof(*adn)); + + /* empty */ + subscr->msisdn[0] = '\0'; + if (adn->len_bcd <= 1) + return 0; + + /* number */ + if (adn->ton_npi == 1) + strcpy(subscr->msisdn, "+"); + if (adn->ton_npi == 2) + strcpy(subscr->msisdn, "0"); + strncat(subscr->msisdn, sim_decode_bcd(adn->number, adn->len_bcd - 1), + sizeof(subscr->msisdn) - 2); + + LOGP(DMM, LOGL_INFO, "received MSISDN %s from SIM\n", subscr->msisdn); + + return 0; +} + +static int subscr_sim_kc(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + + if (length < 9) + return -EINVAL; + + /* key */ + memcpy(subscr->key, data, 8); + + /* key sequence */ + subscr->key_seq = data[8] & 0x07; + + LOGP(DMM, LOGL_INFO, "received KEY from SIM\n"); + + return 0; +} + +static int subscr_sim_plmnsel(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct gsm_sub_plmn_list *plmn; + struct llist_head *lh, *lh2; + uint8_t lai[5]; + uint16_t dummy_lac; + + /* flush list */ + llist_for_each_safe(lh, lh2, &subscr->plmn_list) { + llist_del(lh); + talloc_free(lh); + } + + while(length >= 3) { + /* end of list inside mandatory fields */ + if (data[0] == 0xff && data[1] == 0xff && data[2] == 0x0ff) + break; + + /* add to list */ + plmn = talloc_zero(l23_ctx, struct gsm_sub_plmn_list); + if (!plmn) + return -ENOMEM; + lai[0] = data[0]; + lai[1] = data[1]; + lai[2] = data[2]; + gsm48_decode_lai((struct gsm48_loc_area_id *)lai, &plmn->mcc, + &plmn->mnc, &dummy_lac); + llist_add_tail(&plmn->entry, &subscr->plmn_list); + + LOGP(DMM, LOGL_INFO, "received PLMN selector (mcc=%s mnc=%s) " + "from SIM\n", + gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc)); + + data += 3; + length -= 3; + } + + return 0; +} + +static int subscr_sim_hpplmn(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + + if (length < 1) + return -EINVAL; + + /* HPLMN search interval */ + subscr->t6m_hplmn = *data; /* multiple of 6 minutes */ + + LOGP(DMM, LOGL_INFO, "received HPPLMN %d from SIM\n", + subscr->t6m_hplmn); + + return 0; +} + +static int subscr_sim_spn(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + int i; + + /* UCS2 code not supported */ + if (length < 17 || data[1] >= 0x80) + return -ENOTSUP; + + data++; + for (i = 0; i < 16; i++) { + if (*data == 0xff) + break; + subscr->sim_spn[i] = *data++; + } + subscr->sim_spn[i] = '\0'; + + LOGP(DMM, LOGL_INFO, "received SPN %s from SIM\n", subscr->sim_spn); + + return 0; +} + +static int subscr_sim_acc(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + uint16_t ac; + + if (length < 2) + return -EINVAL; + + /* cell access */ + memcpy(&ac, data, sizeof(ac)); + subscr->acc_class = ntohs(ac); + + LOGP(DMM, LOGL_INFO, "received ACC %04x from SIM\n", subscr->acc_class); + + return 0; +} + +static int subscr_sim_fplmn(struct osmocom_ms *ms, uint8_t *data, + uint8_t length) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct gsm_sub_plmn_na *na; + struct llist_head *lh, *lh2; + uint8_t lai[5]; + uint16_t dummy_lac; + + /* flush list */ + llist_for_each_safe(lh, lh2, &subscr->plmn_na) { + llist_del(lh); + talloc_free(lh); + } + + while (length >= 3) { + /* end of list inside mandatory fields */ + if (data[0] == 0xff && data[1] == 0xff && data[2] == 0x0ff) + break; + + /* add to list */ + na = talloc_zero(l23_ctx, struct gsm_sub_plmn_na); + if (!na) + return -ENOMEM; + lai[0] = data[0]; + lai[1] = data[1]; + lai[2] = data[2]; + gsm48_decode_lai((struct gsm48_loc_area_id *)lai, &na->mcc, + &na->mnc, &dummy_lac); + na->cause = 0; + llist_add_tail(&na->entry, &subscr->plmn_na); + + data += 3; + length -= 3; + } + return 0; +} + +static struct subscr_sim_file { + uint8_t mandatory; + uint16_t path[MAX_SIM_PATH_LENGTH]; + uint16_t file; + int (*func)(struct osmocom_ms *ms, uint8_t *data, + uint8_t length); +} subscr_sim_files[] = { + { 1, { 0 }, 0x2fe2, subscr_sim_iccid }, + { 1, { 0x7f20, 0 }, 0x6f07, subscr_sim_imsi }, + { 1, { 0x7f20, 0 }, 0x6f7e, subscr_sim_loci }, + { 0, { 0x7f20, 0 }, 0x6f40, subscr_sim_msisdn }, + { 0, { 0x7f20, 0 }, 0x6f20, subscr_sim_kc }, + { 0, { 0x7f20, 0 }, 0x6f30, subscr_sim_plmnsel }, + { 0, { 0x7f20, 0 }, 0x6f31, subscr_sim_hpplmn }, + { 0, { 0x7f20, 0 }, 0x6f46, subscr_sim_spn }, + { 0, { 0x7f20, 0 }, 0x6f78, subscr_sim_acc }, + { 0, { 0x7f20, 0 }, 0x6f7b, subscr_sim_fplmn }, + { 0, { 0 }, 0, NULL } +}; + +/* request file from SIM */ +static int subscr_sim_request(struct osmocom_ms *ms) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct subscr_sim_file *sf = &subscr_sim_files[subscr->sim_file_index]; + struct msgb *nmsg; + struct sim_hdr *nsh; + int i; + + /* we are done, fire up PLMN and cell selection process */ + if (!sf->func) { + LOGP(DMM, LOGL_INFO, "(ms %s) Done reading SIM card " + "(IMSI=%s %s, %s)\n", ms->name, subscr->imsi, + gsm_imsi_mcc(subscr->imsi), gsm_imsi_mnc(subscr->imsi)); + + /* if LAI is valid, set RPLMN */ + if (subscr->lac > 0x0000 && subscr->lac < 0xfffe) { + subscr->plmn_valid = 1; + subscr->plmn_mcc = subscr->mcc; + subscr->plmn_mnc = subscr->mnc; + LOGP(DMM, LOGL_INFO, "-> SIM card registered to %s %s " + "(%s, %s)\n", gsm_print_mcc(subscr->plmn_mcc), + gsm_print_mnc(subscr->plmn_mnc), + gsm_get_mcc(subscr->plmn_mcc), + gsm_get_mnc(subscr->plmn_mcc, + subscr->plmn_mnc)); + } else + LOGP(DMM, LOGL_INFO, "-> SIM card not registered\n"); + + /* insert card */ + nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_REG_REQ); + if (!nmsg) + return -ENOMEM; + gsm48_mmr_downmsg(ms, nmsg); + + return 0; + } + + /* trigger SIM reading */ + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_query, + SIM_JOB_READ_BINARY); + if (!nmsg) + return -ENOMEM; + nsh = (struct sim_hdr *) nmsg->data; + i = 0; + while (sf->path[i]) { + nsh->path[i] = sf->path[i]; + i++; + } + nsh->path[i] = 0; /* end of path */ + nsh->file = sf->file; + LOGP(DMM, LOGL_INFO, "Requesting SIM file 0x%04x\n", nsh->file); + sim_job(ms, nmsg); + + return 0; +} + +static void subscr_sim_query_cb(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct sim_hdr *sh = (struct sim_hdr *) msg->data; + uint8_t *payload = msg->data + sizeof(*sh); + uint16_t payload_len = msg->len - sizeof(*sh); + int rc; + + /* error handling */ + if (sh->job_type == SIM_JOB_ERROR) { + uint8_t cause = payload[0]; + + switch (cause) { + /* unlocking required */ + case SIM_CAUSE_PIN1_REQUIRED: + LOGP(DMM, LOGL_INFO, "PIN is required, %d tries left\n", + payload[1]); + + vty_notify(ms, NULL); + vty_notify(ms, "Please give PIN for ICCID %s (you have " + "%d tries left)\n", subscr->iccid, payload[1]); + subscr->sim_pin_required = 1; + break; + case SIM_CAUSE_PIN1_BLOCKED: + LOGP(DMM, LOGL_NOTICE, "PIN is blocked\n"); + + vty_notify(ms, NULL); + vty_notify(ms, "PIN is blocked\n"); + break; + default: + LOGP(DMM, LOGL_NOTICE, "SIM reading failed\n"); + + vty_notify(ms, NULL); + vty_notify(ms, "SIM failed, replace SIM!\n"); + } + msgb_free(msg); + + return; + } + + /* call function do decode SIM reply */ + rc = subscr_sim_files[subscr->sim_file_index].func(ms, payload, + payload_len); + + if (rc) { + LOGP(DMM, LOGL_NOTICE, "SIM reading failed, file invalid\n"); + if (subscr_sim_files[subscr->sim_file_index].mandatory) { + vty_notify(ms, NULL); + vty_notify(ms, "SIM failed, data invalid, replace " + "SIM!\n"); + msgb_free(msg); + + return; + } + } + + msgb_free(msg); + + /* trigger next file */ + subscr->sim_file_index++; + subscr_sim_request(ms); +} + +/* enter PIN */ +void gsm_subscr_sim_pin(struct osmocom_ms *ms, char *pin) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct msgb *nmsg; + + if (!subscr->sim_pin_required) { + LOGP(DMM, LOGL_ERROR, "No PIN required now\n"); + return; + } + + subscr->sim_pin_required = 0; + LOGP(DMM, LOGL_INFO, "Unlocking PIN %s\n", pin); + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_update, + SIM_JOB_PIN1_UNLOCK); + if (!nmsg) + return; + memcpy(msgb_put(nmsg, strlen(pin)), pin, strlen(pin)); + sim_job(ms, nmsg); +} + +/* Attach SIM reader, no SIM must be currently attached */ +int gsm_subscr_simcard(struct osmocom_ms *ms) +{ + struct gsm_subscriber *subscr = &ms->subscr; + + if (subscr->sim_valid) { + LOGP(DMM, LOGL_ERROR, "Cannot attach card, until current card " + "is detached.\n"); + return -EBUSY; + } + + /* reset subscriber */ + gsm_subscr_exit(ms); + gsm_subscr_init(ms); + + subscr->sim_type = GSM_SIM_TYPE_READER; + sprintf(subscr->sim_name, "sim"); + subscr->sim_valid = 1; + subscr->ustate = GSM_SIM_U2_NOT_UPDATED; + + /* start with first index */ + subscr->sim_file_index = 0; + return subscr_sim_request(ms); +} + +/* update plmn not allowed list on SIM */ +static int subscr_write_plmn_na(struct osmocom_ms *ms) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct msgb *nmsg; + struct sim_hdr *nsh; + struct gsm_sub_plmn_na *na, *nas[4] = { NULL, NULL, NULL, NULL }; + int count = 0, i; + uint8_t *data; + uint8_t lai[5]; + + /* skip, if no real valid SIM */ + if (subscr->sim_type != GSM_SIM_TYPE_READER || !subscr->sim_valid) + return 0; + + /* get tail list from "PLMN not allowed" */ + llist_for_each_entry(na, &subscr->plmn_na, entry) { + if (count < 4) + nas[count] = na; + else { + nas[0] = nas[1]; + nas[1] = nas[2]; + nas[2] = nas[3]; + nas[3] = na; + } + count++; + } + + /* write to SIM */ + LOGP(DMM, LOGL_INFO, "Updating FPLMN on SIM\n"); + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_update, + SIM_JOB_UPDATE_BINARY); + if (!nmsg) + return -ENOMEM; + nsh = (struct sim_hdr *) nmsg->data; + data = msgb_put(nmsg, 12); + nsh->path[0] = 0x7f20; + nsh->path[1] = 0; + nsh->file = 0x6f7b; + for (i = 0; i < 4; i++) { + if (nas[i]) { + gsm48_encode_lai((struct gsm48_loc_area_id *)lai, + nas[i]->mcc, nas[i]->mnc, 0); + *data++ = lai[0]; + *data++ = lai[1]; + *data++ = lai[2]; + } else { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0xff; + } + } + sim_job(ms, nmsg); + + return 0; +} + +/* update LOCI on SIM */ +int gsm_subscr_write_loci(struct osmocom_ms *ms) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct msgb *nmsg; + struct sim_hdr *nsh; + struct gsm1111_ef_loci *loci; + + /* skip, if no real valid SIM */ + if (subscr->sim_type != GSM_SIM_TYPE_READER || !subscr->sim_valid) + return 0; + + LOGP(DMM, LOGL_INFO, "Updating LOCI on SIM\n"); + + /* write to SIM */ + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_update, + SIM_JOB_UPDATE_BINARY); + if (!nmsg) + return -ENOMEM; + nsh = (struct sim_hdr *) nmsg->data; + nsh->path[0] = 0x7f20; + nsh->path[1] = 0; + nsh->file = 0x6f7e; + loci = (struct gsm1111_ef_loci *)msgb_put(nmsg, sizeof(*loci)); + + /* TMSI */ + loci->tmsi = htonl(subscr->tmsi); + + /* LAI */ + gsm48_encode_lai(&loci->lai, subscr->mcc, subscr->mnc, subscr->lac); + + /* TMSI time */ + loci->tmsi_time = 0xff; + + /* location update status */ + switch (subscr->ustate) { + case GSM_SIM_U1_UPDATED: + loci->lupd_status = 0x00; + break; + case GSM_SIM_U3_ROAMING_NA: + loci->lupd_status = 0x03; + break; + default: + loci->lupd_status = 0x01; + } + + sim_job(ms, nmsg); + + return 0; +} + +static void subscr_sim_update_cb(struct osmocom_ms *ms, struct msgb *msg) +{ + struct sim_hdr *sh = (struct sim_hdr *) msg->data; + uint8_t *payload = msg->data + sizeof(*sh); + + /* error handling */ + if (sh->job_type == SIM_JOB_ERROR) + LOGP(DMM, LOGL_NOTICE, "SIM update failed (cause %d)\n", + *payload); + + msgb_free(msg); +} + +int gsm_subscr_generate_kc(struct osmocom_ms *ms, uint8_t key_seq, + uint8_t *rand) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct msgb *nmsg; + struct sim_hdr *nsh; + + /* not a SIM */ + if (subscr->sim_type != GSM_SIM_TYPE_READER || !subscr->sim_valid) { + struct gsm48_mm_event *nmme; + + LOGP(DMM, LOGL_INFO, "Sending fake authentication response\n"); + nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_AUTH_RESPONSE); + if (!nmsg) + return -ENOMEM; + nmme = (struct gsm48_mm_event *)msgb_put(nmsg, sizeof(*nmme)); + nmme->sres[0] = 0x12; + nmme->sres[1] = 0x34; + nmme->sres[2] = 0x56; + nmme->sres[3] = 0x78; + gsm48_mmevent_msg(ms, nmsg); + } + + LOGP(DMM, LOGL_INFO, "Generating KEY at SIM\n"); + + /* command to SIM */ + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_key, SIM_JOB_RUN_GSM_ALGO); + if (!nmsg) + return -ENOMEM; + nsh = (struct sim_hdr *) nmsg->data; + nsh->path[0] = 0x7f20; + nsh->path[1] = 0; + + /* random */ + memcpy(msgb_put(nmsg, 16), rand, 16); + + /* store sequence */ + subscr->key_seq = key_seq; + + sim_job(ms, nmsg); + + return 0; +} + +static void subscr_sim_key_cb(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm_subscriber *subscr = &ms->subscr; + struct sim_hdr *sh = (struct sim_hdr *) msg->data; + uint8_t *payload = msg->data + sizeof(*sh); + uint16_t payload_len = msg->len - sizeof(*sh); + struct msgb *nmsg; + struct sim_hdr *nsh; + struct gsm48_mm_event *nmme; + uint8_t *data; + + /* error handling */ + if (sh->job_type == SIM_JOB_ERROR) { + LOGP(DMM, LOGL_NOTICE, "key generation on SIM failed " + "(cause %d)\n", *payload); + + msgb_free(msg); + + return; + } + + if (payload_len < 12) { + LOGP(DMM, LOGL_NOTICE, "response from SIM too short\n"); + return; + } + + /* store key */ + memcpy(subscr->key, payload + 4, 8); + + /* write to SIM */ + LOGP(DMM, LOGL_INFO, "Updating KC on SIM\n"); + nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_update, + SIM_JOB_UPDATE_BINARY); + if (!nmsg) + return; + nsh = (struct sim_hdr *) nmsg->data; + nsh->path[0] = 0x7f20; + nsh->path[1] = 0; + nsh->file = 0x6f20; + data = msgb_put(nmsg, 9); + memcpy(data, subscr->key, 8); + data[8] = subscr->key_seq; + sim_job(ms, nmsg); + + /* return signed response */ + nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_AUTH_RESPONSE); + if (!nmsg) + return; + nmme = (struct gsm48_mm_event *)msgb_put(nmsg, sizeof(*nmme)); + nmme->sres[0] = 0x12; + nmme->sres[1] = 0x34; + nmme->sres[2] = 0x56; + nmme->sres[3] = 0x78; + gsm48_mmevent_msg(ms, nmsg); + + msgb_free(msg); +} + +/* + * detach + */ + /* Detach card */ int gsm_subscr_remove(struct osmocom_ms *ms) { struct gsm_subscriber *subscr = &ms->subscr; - struct msgb *msg; + struct msgb *nmsg; if (!subscr->sim_valid) { LOGP(DMM, LOGL_ERROR, "Cannot remove card, no card present\n"); @@ -131,14 +886,18 @@ int gsm_subscr_remove(struct osmocom_ms *ms) } /* remove card */ - msg = gsm48_mmr_msgb_alloc(GSM48_MMR_NREG_REQ); - if (!msg) + nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_NREG_REQ); + if (!nmsg) return -ENOMEM; - gsm48_mmr_downmsg(ms, msg); + gsm48_mmr_downmsg(ms, nmsg); return 0; } +/* + * state and lists + */ + static const char *subscr_ustate_names[] = { "U0_NULL", "U1_UPDATED", @@ -169,9 +928,8 @@ int gsm_subscr_del_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc, gsm_print_mcc(mcc), gsm_print_mnc(mnc)); llist_del(&na->entry); talloc_free(na); -#ifdef TODO - update plmn not allowed list on sim -#endif + /* update plmn not allowed list on SIM */ + subscr_write_plmn_na(subscr->ms); return 0; } } @@ -185,6 +943,9 @@ int gsm_subscr_add_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc, { struct gsm_sub_plmn_na *na; + /* if already in the list, remove and add to tail */ + gsm_subscr_del_forbidden_plmn(subscr, mcc, mnc); + LOGP(DPLMN, LOGL_INFO, "Add to list of forbidden PLMNs " "(mcc=%s, mnc=%s)\n", gsm_print_mcc(mcc), gsm_print_mnc(mnc)); na = talloc_zero(l23_ctx, struct gsm_sub_plmn_na); @@ -199,9 +960,8 @@ int gsm_subscr_add_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc, if (subscr->sim_valid && gsm_match_mnc(mcc, mnc, subscr->imsi)) return -EINVAL; -#ifdef TODO - update plmn not allowed list on sim -#endif + /* update plmn not allowed list on SIM */ + subscr_write_plmn_na(subscr->ms); return 0; } @@ -252,16 +1012,18 @@ void gsm_subscr_dump(struct gsm_subscriber *subscr, } print(priv, " IMSI: %s\n", subscr->imsi); + if (subscr->msisdn[0]) + print(priv, " MSISDN: %s\n", subscr->msisdn); print(priv, " Status: %s IMSI %s", subscr_ustate_names[subscr->ustate], (subscr->imsi_attached) ? "attached" : "detached"); - if (subscr->tmsi_valid) + if (subscr->tmsi != 0xffffffff) print(priv, " TSMI %08x", subscr->tmsi); - if (subscr->lai_valid) + if (subscr->lac > 0x0000 && subscr->lac < 0xfffe) print(priv, " LAI: MCC %s MNC %s LAC 0x%04x (%s, %s)\n", - gsm_print_mcc(subscr->lai_mcc), - gsm_print_mnc(subscr->lai_mnc), subscr->lai_lac, - gsm_get_mcc(subscr->lai_mcc), - gsm_get_mnc(subscr->lai_mcc, subscr->lai_mnc)); + gsm_print_mcc(subscr->mcc), + gsm_print_mnc(subscr->mnc), subscr->lac, + gsm_get_mcc(subscr->mcc), + gsm_get_mnc(subscr->mcc, subscr->mnc)); else print(priv, " LAI: invalid\n"); if (subscr->key_seq != 7) { @@ -271,7 +1033,7 @@ void gsm_subscr_dump(struct gsm_subscriber *subscr, print(priv, "\n"); } if (subscr->plmn_valid) - print(priv, " Current PLMN: MCC %s MNC %s (%s, %s)\n", + print(priv, " Registered PLMN: MCC %s MNC %s (%s, %s)\n", gsm_print_mcc(subscr->plmn_mcc), gsm_print_mnc(subscr->plmn_mnc), gsm_get_mcc(subscr->plmn_mcc), @@ -305,19 +1067,3 @@ void gsm_subscr_dump(struct gsm_subscriber *subscr, } } -char *gsm_check_imsi(const char *imsi) -{ - int i; - - if (!imsi || strlen(imsi) != 15) - return "IMSI must have 15 digits!"; - - for (i = 0; i < strlen(imsi); i++) { - if (imsi[i] < '0' || imsi[i] > '9') - return "IMSI must have digits 0 to 9 only!"; - } - - return NULL; -} - - diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c index 0c207316..8109cb53 100644 --- a/src/host/layer23/src/mobile/vty_interface.c +++ b/src/host/layer23/src/mobile/vty_interface.c @@ -350,7 +350,7 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]", return CMD_WARNING; if (ms->subscr.sim_valid) { - vty_out(vty, "Sim already presend, remove first!%s", + vty_out(vty, "SIM already presend, remove first!%s", VTY_NEWLINE); return CMD_WARNING; } @@ -373,6 +373,26 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]", return CMD_SUCCESS; } +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; + + 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_NEWLINE); + return CMD_WARNING; + } + + gsm_subscr_simcard(ms); + + return CMD_SUCCESS; +} + DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME", "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")") { @@ -392,6 +412,26 @@ DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME", return CMD_SUCCESS; } +DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN", + "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n" + "PIN number") +{ + struct osmocom_ms *ms; + + ms = get_ms(argv[0], vty); + if (!ms) + return CMD_WARNING; + + if (!ms->subscr.sim_pin_required) { + vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + gsm_subscr_sim_pin(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") @@ -610,12 +650,12 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) struct gsm_settings *set = &ms->settings; vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE); - switch(set->simtype) { + switch(set->sim_type) { case GSM_SIM_TYPE_NONE: vty_out(vty, " sim none%s", VTY_NEWLINE); break; - case GSM_SIM_TYPE_SLOT: - vty_out(vty, " sim slot%s", VTY_NEWLINE); + case GSM_SIM_TYPE_READER: + vty_out(vty, " sim reader%s", VTY_NEWLINE); break; case GSM_SIM_TYPE_TEST: vty_out(vty, " sim test%s", VTY_NEWLINE); @@ -696,22 +736,25 @@ static int config_write_ms(struct vty *vty) return CMD_SUCCESS; } -DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|test)", - "Set sim card type when powering on\nNo sim interted\n" - "Test sim inserted") +DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)", + "Set SIM card type when powering on\nNo SIM interted\n" + "Use SIM from reader\nTest SIM inserted") { struct osmocom_ms *ms = vty->index; switch (argv[0][0]) { case 'n': - ms->settings.simtype = GSM_SIM_TYPE_NONE; + ms->settings.sim_type = GSM_SIM_TYPE_NONE; break; - case 's': - ms->settings.simtype = GSM_SIM_TYPE_SLOT; + case 'r': + ms->settings.sim_type = GSM_SIM_TYPE_READER; break; case 't': - ms->settings.simtype = GSM_SIM_TYPE_TEST; + ms->settings.sim_type = GSM_SIM_TYPE_TEST; break; + default: + vty_out(vty, "unknown SIM type%s", VTY_NEWLINE); + return CMD_WARNING; } return CMD_SUCCESS; @@ -1143,7 +1186,9 @@ int ms_vty_init(void) install_element_ve(&no_monitor_network_cmd); install_element(ENABLE_NODE, &sim_test_cmd); + install_element(ENABLE_NODE, &sim_reader_cmd); install_element(ENABLE_NODE, &sim_remove_cmd); + install_element(ENABLE_NODE, &sim_pin_cmd); install_element(ENABLE_NODE, &network_search_cmd); install_element(ENABLE_NODE, &network_show_cmd); install_element(ENABLE_NODE, &network_select_cmd); |