[layer23] Layer 3 now uses SIM client to request and update SIM data

The SIM reader can be selected via VTY, but because it is not yet
implemented in layer1, nothing happens when selecting it.
This commit is contained in:
Andreas.Eversberg 2010-08-28 09:46:36 +00:00
parent 4931b324e5
commit f20a1c3de8
9 changed files with 1033 additions and 212 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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;
}

View File

@ -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);