summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h2
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/settings.h2
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/subscriber.h41
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c31
-rw-r--r--src/host/layer23/src/mobile/gsm322.c10
-rw-r--r--src/host/layer23/src/mobile/gsm48_mm.c216
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c46
-rw-r--r--src/host/layer23/src/mobile/subscriber.c830
-rw-r--r--src/host/layer23/src/mobile/vty_interface.c67
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);