2010-04-25 16:28:24 +00:00
|
|
|
/*
|
|
|
|
* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2010-08-28 09:46:36 +00:00
|
|
|
#include <arpa/inet.h>
|
2011-04-26 00:55:30 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/gsm/comp128.h>
|
2010-04-25 16:28:24 +00:00
|
|
|
|
2010-07-27 18:44:46 +00:00
|
|
|
#include <osmocom/bb/common/logging.h>
|
|
|
|
#include <osmocom/bb/common/osmocom_data.h>
|
|
|
|
#include <osmocom/bb/common/networks.h>
|
2010-08-28 09:46:36 +00:00
|
|
|
#include <osmocom/bb/mobile/vty.h>
|
2010-04-25 16:28:24 +00:00
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
/* enable to get an empty list of forbidden PLMNs, even if stored on SIM.
|
|
|
|
* if list is changed, the result is not written back to SIM */
|
|
|
|
//#define TEST_EMPTY_FPLMN
|
|
|
|
|
2010-05-09 16:01:49 +00:00
|
|
|
void *l23_ctx;
|
2010-04-25 16:28:24 +00:00
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
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))
|
2010-09-18 19:15:15 +00:00
|
|
|
c = (data[i >> 1] >> 4);
|
2010-08-28 09:46:36 +00:00
|
|
|
else
|
2010-09-18 19:15:15 +00:00
|
|
|
c = (data[i >> 1] & 0xf);
|
2010-08-28 09:46:36 +00:00
|
|
|
if (c == 0xf)
|
|
|
|
break;
|
2010-09-18 19:15:15 +00:00
|
|
|
result[j++] = c + '0';
|
2010-08-28 09:46:36 +00:00
|
|
|
if (j == sizeof(result) - 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
result[j] = '\0';
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-09-17 15:51:23 +00:00
|
|
|
static void xor96(uint8_t *ki, uint8_t *rand, uint8_t *sres, uint8_t *kc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i < 4; i++)
|
|
|
|
sres[i] = rand[i] ^ ki[i];
|
|
|
|
for (i=0; i < 8; i++)
|
|
|
|
kc[i] = rand[i] ^ ki[i+4];
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/*
|
|
|
|
* init/exit
|
|
|
|
*/
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
int gsm_subscr_init(struct osmocom_ms *ms)
|
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
|
|
|
|
memset(subscr, 0, sizeof(*subscr));
|
|
|
|
subscr->ms = ms;
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* set TMSI / LAC invalid */
|
|
|
|
subscr->tmsi = 0xffffffff;
|
|
|
|
subscr->lac = 0x0000;
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
/* set key invalid */
|
|
|
|
subscr->key_seq = 7;
|
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
/* any cell selection timer timeout */
|
|
|
|
subscr->any_timeout = 30;
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
/* init lists */
|
|
|
|
INIT_LLIST_HEAD(&subscr->plmn_list);
|
|
|
|
INIT_LLIST_HEAD(&subscr->plmn_na);
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* 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);
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gsm_subscr_exit(struct osmocom_ms *ms)
|
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
struct llist_head *lh, *lh2;
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
/* flush lists */
|
|
|
|
llist_for_each_safe(lh, lh2, &subscr->plmn_list) {
|
|
|
|
llist_del(lh);
|
|
|
|
talloc_free(lh);
|
|
|
|
}
|
|
|
|
llist_for_each_safe(lh, lh2, &subscr->plmn_na) {
|
|
|
|
llist_del(lh);
|
|
|
|
talloc_free(lh);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/*
|
|
|
|
* test card
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Attach test card, no SIM must be currently attached */
|
2010-11-20 08:32:32 +00:00
|
|
|
int gsm_subscr_testcard(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc,
|
|
|
|
uint16_t lac, uint32_t tmsi)
|
2010-04-25 16:28:24 +00:00
|
|
|
{
|
2010-05-23 20:53:32 +00:00
|
|
|
struct gsm_settings *set = &ms->settings;
|
2010-04-25 16:28:24 +00:00
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
2010-08-28 09:46:36 +00:00
|
|
|
struct msgb *nmsg;
|
2010-05-23 20:53:32 +00:00
|
|
|
char *error;
|
2010-04-25 16:28:24 +00:00
|
|
|
|
|
|
|
if (subscr->sim_valid) {
|
|
|
|
LOGP(DMM, LOGL_ERROR, "Cannot insert card, until current card "
|
|
|
|
"is detached.\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2010-06-20 11:19:06 +00:00
|
|
|
error = gsm_check_imsi(set->test_imsi);
|
2010-05-23 20:53:32 +00:00
|
|
|
if (error) {
|
|
|
|
LOGP(DMM, LOGL_ERROR, "%s\n", error);
|
2010-04-25 16:28:24 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset subscriber */
|
|
|
|
gsm_subscr_exit(ms);
|
|
|
|
gsm_subscr_init(ms);
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
subscr->sim_type = GSM_SIM_TYPE_TEST;
|
2010-04-25 16:28:24 +00:00
|
|
|
sprintf(subscr->sim_name, "test");
|
|
|
|
subscr->sim_valid = 1;
|
|
|
|
subscr->ustate = GSM_SIM_U2_NOT_UPDATED;
|
2010-05-23 20:53:32 +00:00
|
|
|
subscr->acc_barr = set->test_barr; /* we may access barred cell */
|
2010-05-24 23:15:15 +00:00
|
|
|
subscr->acc_class = 0xffff; /* we have any access class */
|
2010-05-23 20:53:32 +00:00
|
|
|
subscr->plmn_valid = set->test_rplmn_valid;
|
2010-07-22 16:11:28 +00:00
|
|
|
subscr->plmn_mcc = mcc;
|
|
|
|
subscr->plmn_mnc = mnc;
|
2010-11-20 08:32:32 +00:00
|
|
|
subscr->mcc = mcc;
|
|
|
|
subscr->mnc = mnc;
|
|
|
|
subscr->lac = lac;
|
|
|
|
subscr->tmsi = tmsi;
|
2010-05-23 20:53:32 +00:00
|
|
|
subscr->always_search_hplmn = set->test_always;
|
2010-04-25 16:28:24 +00:00
|
|
|
subscr->t6m_hplmn = 1; /* try to find home network every 6 min */
|
2010-05-23 20:53:32 +00:00
|
|
|
strcpy(subscr->imsi, set->test_imsi);
|
2010-04-25 16:28:24 +00:00
|
|
|
|
2010-07-22 16:11:28 +00:00
|
|
|
LOGP(DMM, LOGL_INFO, "(ms %s) Inserting test card (IMSI=%s %s, %s)\n",
|
2010-06-20 11:19:06 +00:00
|
|
|
ms->name, subscr->imsi, gsm_imsi_mcc(subscr->imsi),
|
|
|
|
gsm_imsi_mnc(subscr->imsi));
|
2010-04-25 16:28:24 +00:00
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
if (subscr->plmn_valid)
|
2010-11-20 08:32:32 +00:00
|
|
|
LOGP(DMM, LOGL_INFO, "-> Test card registered to %s %s 0x%04x"
|
|
|
|
"(%s, %s)\n", gsm_print_mcc(mcc),
|
|
|
|
gsm_print_mnc(mnc), lac, gsm_get_mcc(mcc),
|
|
|
|
gsm_get_mnc(mcc, mnc));
|
2010-08-28 09:46:36 +00:00
|
|
|
else
|
|
|
|
LOGP(DMM, LOGL_INFO, "-> Test card not registered\n");
|
2010-07-22 16:11:28 +00:00
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
/* insert card */
|
2010-08-28 09:46:36 +00:00
|
|
|
nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_REG_REQ);
|
|
|
|
if (!nmsg)
|
2010-04-25 16:28:24 +00:00
|
|
|
return -ENOMEM;
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
2010-09-18 19:15:15 +00:00
|
|
|
char *imsi;
|
2010-08-28 09:46:36 +00:00
|
|
|
|
|
|
|
/* 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];
|
2010-09-18 19:15:15 +00:00
|
|
|
|
|
|
|
/* decode IMSI, skip first digit (parity) */
|
|
|
|
imsi = sim_decode_bcd(data + 1, length);
|
|
|
|
if (strlen(imsi) - 1 > GSM_IMSI_LENGTH - 1 || strlen(imsi) - 1 < 6) {
|
2010-08-28 09:46:36 +00:00
|
|
|
LOGP(DMM, LOGL_NOTICE, "IMSI invalid length = %d\n",
|
2010-09-18 19:15:15 +00:00
|
|
|
strlen(imsi) - 1);
|
2010-08-28 09:46:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2010-09-18 19:15:15 +00:00
|
|
|
strncpy(subscr->imsi, imsi + 1, sizeof(subscr->imsi) - 1);
|
2010-08-28 09:46:36 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-09-18 19:15:15 +00:00
|
|
|
LOGP(DMM, LOGL_INFO, "received LOCI from SIM (mcc=%s mnc=%s lac=0x%04x "
|
|
|
|
"U%d)\n", gsm_print_mcc(subscr->mcc),
|
|
|
|
gsm_print_mnc(subscr->mnc), subscr->lac, subscr->ustate);
|
2010-04-25 16:28:24 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
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 */
|
2011-11-01 15:29:18 +00:00
|
|
|
if (((adn->ton_npi & 0x70) >> 4) == 1)
|
2010-08-28 09:46:36 +00:00
|
|
|
strcpy(subscr->msisdn, "+");
|
2011-11-01 15:29:18 +00:00
|
|
|
if (((adn->ton_npi & 0x70) >> 4) == 2)
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-11-01 15:29:18 +00:00
|
|
|
static int subscr_sim_smsp(struct osmocom_ms *ms, uint8_t *data,
|
|
|
|
uint8_t length)
|
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
struct gsm1111_ef_smsp *smsp;
|
|
|
|
|
|
|
|
if (length < sizeof(*smsp))
|
|
|
|
return -EINVAL;
|
|
|
|
smsp = (struct gsm1111_ef_smsp *) (data + length - sizeof(*smsp));
|
|
|
|
|
|
|
|
/* empty */
|
|
|
|
subscr->sms_sca[0] = '\0';
|
|
|
|
|
|
|
|
/* TS-Service Centre Address */
|
|
|
|
if (!(smsp->par_ind & 0x02) && smsp->ts_sca[0] <= 11) {
|
|
|
|
if (((smsp->ts_sca[1] & 0x70) >> 4) == 1)
|
|
|
|
strcpy(subscr->sms_sca, "+");
|
|
|
|
if (((smsp->ts_sca[1] & 0x70) >> 4) == 2)
|
|
|
|
strcpy(subscr->sms_sca, "0");
|
|
|
|
gsm48_decode_bcd_number(subscr->sms_sca +
|
|
|
|
strlen(subscr->sms_sca), sizeof(subscr->sms_sca)
|
|
|
|
- strlen(subscr->sms_sca), smsp->ts_sca, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DMM, LOGL_INFO, "received SMSP from SIM (sca=%s)\n",
|
|
|
|
subscr->sms_sca);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
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 */
|
|
|
|
|
2010-09-18 19:15:15 +00:00
|
|
|
LOGP(DMM, LOGL_INFO, "received HPPLMN %d (%d mins) from SIM\n",
|
|
|
|
subscr->t6m_hplmn, subscr->t6m_hplmn * 6);
|
2010-08-28 09:46:36 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
#ifdef TEST_EMPTY_FPLMN
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* 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);
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
na->cause = -1; /* must have a value, but SIM stores no cause */
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
2011-11-01 15:29:18 +00:00
|
|
|
uint8_t sim_job;
|
2010-08-28 09:46:36 +00:00
|
|
|
int (*func)(struct osmocom_ms *ms, uint8_t *data,
|
|
|
|
uint8_t length);
|
|
|
|
} subscr_sim_files[] = {
|
2011-11-01 15:29:18 +00:00
|
|
|
{ 1, { 0 }, 0x2fe2, SIM_JOB_READ_BINARY, subscr_sim_iccid },
|
|
|
|
{ 1, { 0x7f20, 0 }, 0x6f07, SIM_JOB_READ_BINARY, subscr_sim_imsi },
|
|
|
|
{ 1, { 0x7f20, 0 }, 0x6f7e, SIM_JOB_READ_BINARY, subscr_sim_loci },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f20, SIM_JOB_READ_BINARY, subscr_sim_kc },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f30, SIM_JOB_READ_BINARY, subscr_sim_plmnsel },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f31, SIM_JOB_READ_BINARY, subscr_sim_hpplmn },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f46, SIM_JOB_READ_BINARY, subscr_sim_spn },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f78, SIM_JOB_READ_BINARY, subscr_sim_acc },
|
|
|
|
{ 0, { 0x7f20, 0 }, 0x6f7b, SIM_JOB_READ_BINARY, subscr_sim_fplmn },
|
|
|
|
{ 0, { 0x7f10, 0 }, 0x6f40, SIM_JOB_READ_RECORD, subscr_sim_msisdn },
|
|
|
|
{ 0, { 0x7f10, 0 }, 0x6f42, SIM_JOB_READ_RECORD, subscr_sim_smsp },
|
|
|
|
{ 0, { 0 }, 0, 0, NULL }
|
2010-08-28 09:46:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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,
|
2011-11-01 15:29:18 +00:00
|
|
|
sf->sim_job);
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
2011-11-01 15:29:18 +00:00
|
|
|
nsh->rec_no = 1;
|
|
|
|
nsh->rec_mode = 0x04;
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
2010-09-19 10:52:42 +00:00
|
|
|
struct subscr_sim_file *sf = &subscr_sim_files[subscr->sim_file_index];
|
2011-06-26 08:40:56 +00:00
|
|
|
struct msgb *nmsg;
|
2010-08-28 09:46:36 +00:00
|
|
|
|
|
|
|
/* 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");
|
2010-09-19 10:52:42 +00:00
|
|
|
if (payload[1]) {
|
|
|
|
vty_notify(ms, "Please give PUC for ICCID %s "
|
|
|
|
"(you have %d tries left)\n",
|
|
|
|
subscr->iccid, payload[1]);
|
|
|
|
}
|
|
|
|
subscr->sim_pin_required = 1;
|
|
|
|
break;
|
|
|
|
case SIM_CAUSE_PUC_BLOCKED:
|
|
|
|
LOGP(DMM, LOGL_NOTICE, "PUC is blocked\n");
|
|
|
|
|
|
|
|
vty_notify(ms, NULL);
|
|
|
|
vty_notify(ms, "PUC is blocked\n");
|
|
|
|
subscr->sim_pin_required = 1;
|
2010-08-28 09:46:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-09-19 10:52:42 +00:00
|
|
|
if (sf->func && !sf->mandatory) {
|
2010-09-18 19:15:15 +00:00
|
|
|
LOGP(DMM, LOGL_NOTICE, "SIM reading failed, "
|
|
|
|
"ignoring!\n");
|
|
|
|
goto ignore;
|
|
|
|
}
|
2010-08-28 09:46:36 +00:00
|
|
|
LOGP(DMM, LOGL_NOTICE, "SIM reading failed\n");
|
|
|
|
|
|
|
|
vty_notify(ms, NULL);
|
|
|
|
vty_notify(ms, "SIM failed, replace SIM!\n");
|
2011-06-26 08:40:56 +00:00
|
|
|
|
|
|
|
/* detach simcard */
|
|
|
|
subscr->sim_valid = 0;
|
|
|
|
nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_NREG_REQ);
|
|
|
|
if (!nmsg)
|
|
|
|
return;
|
|
|
|
gsm48_mmr_downmsg(ms, nmsg);
|
2010-08-28 09:46:36 +00:00
|
|
|
}
|
|
|
|
msgb_free(msg);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-19 10:52:42 +00:00
|
|
|
/* if pin was successfully unlocked, then resend request */
|
|
|
|
if (subscr->sim_pin_required) {
|
|
|
|
subscr->sim_pin_required = 0;
|
|
|
|
subscr_sim_request(ms);
|
|
|
|
return;
|
|
|
|
}
|
2010-08-28 09:46:36 +00:00
|
|
|
|
2010-09-19 10:52:42 +00:00
|
|
|
/* done when nothing more to read. this happens on PIN requests */
|
|
|
|
if (!sf->func)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* call function do decode SIM reply */
|
|
|
|
rc = sf->func(ms, payload, payload_len);
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-18 19:15:15 +00:00
|
|
|
ignore:
|
2010-08-28 09:46:36 +00:00
|
|
|
msgb_free(msg);
|
|
|
|
|
|
|
|
/* trigger next file */
|
|
|
|
subscr->sim_file_index++;
|
|
|
|
subscr_sim_request(ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enter PIN */
|
2010-09-19 10:52:42 +00:00
|
|
|
void gsm_subscr_sim_pin(struct osmocom_ms *ms, char *pin1, char *pin2,
|
|
|
|
int8_t mode)
|
2010-08-28 09:46:36 +00:00
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
struct msgb *nmsg;
|
2010-09-19 10:52:42 +00:00
|
|
|
uint8_t job;
|
2010-08-28 09:46:36 +00:00
|
|
|
|
2010-09-26 21:08:53 +00:00
|
|
|
/* skip, if no real valid SIM */
|
|
|
|
if (subscr->sim_type != GSM_SIM_TYPE_READER)
|
|
|
|
return;
|
|
|
|
|
2010-09-19 10:52:42 +00:00
|
|
|
switch (mode) {
|
|
|
|
case -1:
|
|
|
|
job = SIM_JOB_PIN1_DISABLE;
|
|
|
|
LOGP(DMM, LOGL_INFO, "disabling PIN %s\n", pin1);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
job = SIM_JOB_PIN1_ENABLE;
|
|
|
|
LOGP(DMM, LOGL_INFO, "enabling PIN %s\n", pin1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
job = SIM_JOB_PIN1_CHANGE;
|
|
|
|
LOGP(DMM, LOGL_INFO, "changing PIN %s to %s\n", pin1, pin2);
|
|
|
|
break;
|
|
|
|
case 99:
|
|
|
|
job = SIM_JOB_PIN1_UNBLOCK;
|
|
|
|
LOGP(DMM, LOGL_INFO, "unblocking PIN %s with PUC %s\n", pin1,
|
|
|
|
pin2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (!subscr->sim_pin_required) {
|
|
|
|
LOGP(DMM, LOGL_ERROR, "No PIN required now\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
LOGP(DMM, LOGL_INFO, "entering PIN %s\n", pin1);
|
|
|
|
job = SIM_JOB_PIN1_UNLOCK;
|
2010-08-28 09:46:36 +00:00
|
|
|
}
|
|
|
|
|
2010-09-19 10:52:42 +00:00
|
|
|
nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_query, job);
|
2010-08-28 09:46:36 +00:00
|
|
|
if (!nmsg)
|
|
|
|
return;
|
2010-09-19 10:52:42 +00:00
|
|
|
memcpy(msgb_put(nmsg, strlen(pin1) + 1), pin1, strlen(pin1) + 1);
|
|
|
|
memcpy(msgb_put(nmsg, strlen(pin2) + 1), pin2, strlen(pin2) + 1);
|
2010-08-28 09:46:36 +00:00
|
|
|
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];
|
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
#ifdef TEST_EMPTY_FPLMN
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* 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,
|
2010-08-29 11:05:07 +00:00
|
|
|
uint8_t *rand, uint8_t no_sim)
|
2010-08-28 09:46:36 +00:00
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
struct msgb *nmsg;
|
|
|
|
struct sim_hdr *nsh;
|
|
|
|
|
|
|
|
/* not a SIM */
|
2010-09-17 15:51:23 +00:00
|
|
|
if ((subscr->sim_type != GSM_SIM_TYPE_READER
|
|
|
|
&& subscr->sim_type != GSM_SIM_TYPE_TEST)
|
|
|
|
|| !subscr->sim_valid || no_sim) {
|
2010-08-28 09:46:36 +00:00
|
|
|
struct gsm48_mm_event *nmme;
|
|
|
|
|
2010-08-29 11:05:07 +00:00
|
|
|
LOGP(DMM, LOGL_INFO, "Sending dummy authentication response\n");
|
2010-08-28 09:46:36 +00:00
|
|
|
nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_AUTH_RESPONSE);
|
|
|
|
if (!nmsg)
|
|
|
|
return -ENOMEM;
|
2010-08-29 08:57:23 +00:00
|
|
|
nmme = (struct gsm48_mm_event *) nmsg->data;
|
2010-08-28 09:46:36 +00:00
|
|
|
nmme->sres[0] = 0x12;
|
|
|
|
nmme->sres[1] = 0x34;
|
|
|
|
nmme->sres[2] = 0x56;
|
|
|
|
nmme->sres[3] = 0x78;
|
|
|
|
gsm48_mmevent_msg(ms, nmsg);
|
2010-08-29 08:57:23 +00:00
|
|
|
|
|
|
|
return 0;
|
2010-08-28 09:46:36 +00:00
|
|
|
}
|
|
|
|
|
2010-09-17 15:51:23 +00:00
|
|
|
/* test SIM */
|
|
|
|
if (subscr->sim_type == GSM_SIM_TYPE_TEST) {
|
|
|
|
struct gsm48_mm_event *nmme;
|
|
|
|
uint8_t sres[4];
|
|
|
|
struct gsm_settings *set = &ms->settings;
|
|
|
|
|
|
|
|
if (set->test_ki_type == GSM_SIM_KEY_COMP128)
|
2010-09-17 18:55:20 +00:00
|
|
|
comp128(set->test_ki, rand, sres, subscr->key);
|
2010-09-17 15:51:23 +00:00
|
|
|
else
|
|
|
|
xor96(set->test_ki, rand, sres, subscr->key);
|
|
|
|
/* store sequence */
|
|
|
|
subscr->key_seq = key_seq;
|
|
|
|
|
|
|
|
LOGP(DMM, LOGL_INFO, "Sending authentication response\n");
|
|
|
|
nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_AUTH_RESPONSE);
|
|
|
|
if (!nmsg)
|
|
|
|
return -ENOMEM;
|
|
|
|
nmme = (struct gsm48_mm_event *) nmsg->data;
|
|
|
|
memcpy(nmme->sres, sres, 4);
|
|
|
|
gsm48_mmevent_msg(ms, nmsg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
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;
|
2010-08-29 08:57:23 +00:00
|
|
|
nmme = (struct gsm48_mm_event *) nmsg->data;
|
2010-09-17 15:51:23 +00:00
|
|
|
memcpy(nmme->sres, payload, 4);
|
2010-08-28 09:46:36 +00:00
|
|
|
gsm48_mmevent_msg(ms, nmsg);
|
|
|
|
|
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* detach
|
|
|
|
*/
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
/* Detach card */
|
|
|
|
int gsm_subscr_remove(struct osmocom_ms *ms)
|
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
2010-08-28 09:46:36 +00:00
|
|
|
struct msgb *nmsg;
|
2010-04-25 16:28:24 +00:00
|
|
|
|
|
|
|
if (!subscr->sim_valid) {
|
|
|
|
LOGP(DMM, LOGL_ERROR, "Cannot remove card, no card present\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove card */
|
2010-08-28 09:46:36 +00:00
|
|
|
nmsg = gsm48_mmr_msgb_alloc(GSM48_MMR_NREG_REQ);
|
|
|
|
if (!nmsg)
|
2010-04-25 16:28:24 +00:00
|
|
|
return -ENOMEM;
|
2010-08-28 09:46:36 +00:00
|
|
|
gsm48_mmr_downmsg(ms, nmsg);
|
2010-04-25 16:28:24 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/*
|
|
|
|
* state and lists
|
|
|
|
*/
|
|
|
|
|
2010-04-25 16:28:24 +00:00
|
|
|
static const char *subscr_ustate_names[] = {
|
|
|
|
"U0_NULL",
|
|
|
|
"U1_UPDATED",
|
|
|
|
"U2_NOT_UPDATED",
|
|
|
|
"U3_ROAMING_NA"
|
|
|
|
};
|
|
|
|
|
|
|
|
/* change to new U state */
|
|
|
|
void new_sim_ustate(struct gsm_subscriber *subscr, int state)
|
|
|
|
{
|
|
|
|
LOGP(DMM, LOGL_INFO, "(ms %s) new state %s -> %s\n", subscr->ms->name,
|
|
|
|
subscr_ustate_names[subscr->ustate],
|
|
|
|
subscr_ustate_names[state]);
|
|
|
|
|
|
|
|
subscr->ustate = state;
|
|
|
|
}
|
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
/* del forbidden PLMN. if MCC==0, flush complete list */
|
2010-05-09 16:01:49 +00:00
|
|
|
int gsm_subscr_del_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
|
|
|
|
uint16_t mnc)
|
|
|
|
{
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
struct gsm_sub_plmn_na *na, *na2;
|
|
|
|
int deleted = 0;
|
2010-05-09 16:01:49 +00:00
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
llist_for_each_entry_safe(na, na2, &subscr->plmn_na, entry) {
|
|
|
|
if (!mcc || (na->mcc == mcc && na->mnc == mnc)) {
|
2010-05-09 16:01:49 +00:00
|
|
|
LOGP(DPLMN, LOGL_INFO, "Delete from list of forbidden "
|
2010-06-20 11:19:06 +00:00
|
|
|
"PLMNs (mcc=%s, mnc=%s)\n",
|
|
|
|
gsm_print_mcc(mcc), gsm_print_mnc(mnc));
|
2010-05-09 16:01:49 +00:00
|
|
|
llist_del(&na->entry);
|
|
|
|
talloc_free(na);
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
deleted = 1;
|
|
|
|
if (mcc)
|
|
|
|
break;
|
2010-05-09 16:01:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
if (deleted) {
|
|
|
|
/* update plmn not allowed list on SIM */
|
|
|
|
subscr_write_plmn_na(subscr->ms);
|
|
|
|
}
|
|
|
|
|
2010-05-09 16:01:49 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add forbidden PLMN */
|
|
|
|
int gsm_subscr_add_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
|
|
|
|
uint16_t mnc, uint8_t cause)
|
|
|
|
{
|
|
|
|
struct gsm_sub_plmn_na *na;
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* if already in the list, remove and add to tail */
|
|
|
|
gsm_subscr_del_forbidden_plmn(subscr, mcc, mnc);
|
|
|
|
|
2010-05-09 16:01:49 +00:00
|
|
|
LOGP(DPLMN, LOGL_INFO, "Add to list of forbidden PLMNs "
|
2010-06-20 11:19:06 +00:00
|
|
|
"(mcc=%s, mnc=%s)\n", gsm_print_mcc(mcc), gsm_print_mnc(mnc));
|
2010-05-09 16:01:49 +00:00
|
|
|
na = talloc_zero(l23_ctx, struct gsm_sub_plmn_na);
|
|
|
|
if (!na)
|
|
|
|
return -ENOMEM;
|
|
|
|
na->mcc = mcc;
|
|
|
|
na->mnc = mnc;
|
[layer23/mobile] Improvement and fixes of idle mode process
This patch introduces cell re-relection. When camping on a cell, it
scanns neighbour cells. If a 'better' cell is found, the cell is selected.
If the cell is in a different location area, a location upating is
performed under certain conditions.
The 'better' cell depends on various informations that are broadcasted on
the BCCH of a neihbour cell and of course the RX level. Most operators
don't set these informations, so the 'better' cell depend on a better
RX level for the same location area, or a much better RX level (6 dBm)
at a different location area.
There were many issues at the idle mode process that has been fixed.
Expecially when moving, the state machines got stuck, so no more cell search
was possible, or no further calls / location updating was possible.
In order to see the process of cell selection, enter the VTY interface and
enable the network monitor:
enable
monitor network 1 (where '1' is the instance of the MS)
In order to see the current state of the processes, enter:
show ms
2011-07-17 09:12:15 +00:00
|
|
|
na->cause = cause ? : -1; /* cause 0 is not allowed */
|
2010-05-09 16:01:49 +00:00
|
|
|
llist_add_tail(&na->entry, &subscr->plmn_na);
|
|
|
|
|
2010-07-19 09:37:57 +00:00
|
|
|
/* don't add Home PLMN to SIM */
|
|
|
|
if (subscr->sim_valid && gsm_match_mnc(mcc, mnc, subscr->imsi))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2010-08-28 09:46:36 +00:00
|
|
|
/* update plmn not allowed list on SIM */
|
|
|
|
subscr_write_plmn_na(subscr->ms);
|
2010-05-09 16:01:49 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* search forbidden PLMN */
|
|
|
|
int gsm_subscr_is_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
|
|
|
|
uint16_t mnc)
|
|
|
|
{
|
|
|
|
struct gsm_sub_plmn_na *na;
|
|
|
|
|
|
|
|
llist_for_each_entry(na, &subscr->plmn_na, entry) {
|
|
|
|
if (na->mcc == mcc && na->mnc == mnc)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-13 13:51:30 +00:00
|
|
|
int gsm_subscr_dump_forbidden_plmn(struct osmocom_ms *ms,
|
|
|
|
void (*print)(void *, const char *, ...), void *priv)
|
|
|
|
{
|
|
|
|
struct gsm_subscriber *subscr = &ms->subscr;
|
|
|
|
struct gsm_sub_plmn_na *temp;
|
|
|
|
|
|
|
|
print(priv, "MCC |MNC |cause\n");
|
|
|
|
print(priv, "-------+-------+-------\n");
|
|
|
|
llist_for_each_entry(temp, &subscr->plmn_na, entry)
|
2010-06-26 13:56:01 +00:00
|
|
|
print(priv, "%s |%s%s |#%d\n",
|
|
|
|
gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
|
|
|
|
((temp->mnc & 0x00f) == 0x00f) ? " ":"", temp->cause);
|
2010-06-13 13:51:30 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-09 16:01:49 +00:00
|
|
|
/* dump subscriber */
|
|
|
|
void gsm_subscr_dump(struct gsm_subscriber *subscr,
|
|
|
|
void (*print)(void *, const char *, ...), void *priv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct gsm_sub_plmn_list *plmn_list;
|
|
|
|
struct gsm_sub_plmn_na *plmn_na;
|
|
|
|
|
|
|
|
print(priv, "Mobile Subscriber of MS '%s':\n", subscr->ms->name);
|
|
|
|
|
|
|
|
if (!subscr->sim_valid) {
|
|
|
|
print(priv, " No SIM present.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-20 11:19:06 +00:00
|
|
|
print(priv, " IMSI: %s\n", subscr->imsi);
|
2010-09-19 13:51:15 +00:00
|
|
|
if (subscr->iccid[0])
|
|
|
|
print(priv, " ICCID: %s\n", subscr->iccid);
|
|
|
|
if (subscr->sim_spn[0])
|
|
|
|
print(priv, " Service Provider Name: %s\n", subscr->sim_spn);
|
2010-08-28 09:46:36 +00:00
|
|
|
if (subscr->msisdn[0])
|
|
|
|
print(priv, " MSISDN: %s\n", subscr->msisdn);
|
2011-11-01 15:29:18 +00:00
|
|
|
if (subscr->sms_sca[0])
|
|
|
|
print(priv, " SMS Service Center Address: %s\n",
|
|
|
|
subscr->sms_sca);
|
2010-05-09 16:01:49 +00:00
|
|
|
print(priv, " Status: %s IMSI %s", subscr_ustate_names[subscr->ustate],
|
|
|
|
(subscr->imsi_attached) ? "attached" : "detached");
|
2010-08-28 09:46:36 +00:00
|
|
|
if (subscr->tmsi != 0xffffffff)
|
2010-09-19 13:51:15 +00:00
|
|
|
print(priv, " TSMI 0x%08x", subscr->tmsi);
|
|
|
|
if (subscr->lac > 0x0000 && subscr->lac < 0xfffe) {
|
|
|
|
print(priv, "\n");
|
|
|
|
print(priv, " LAI: MCC %s MNC %s LAC 0x%04x "
|
|
|
|
"(%s, %s)\n", gsm_print_mcc(subscr->mcc),
|
2010-08-28 09:46:36 +00:00
|
|
|
gsm_print_mnc(subscr->mnc), subscr->lac,
|
|
|
|
gsm_get_mcc(subscr->mcc),
|
|
|
|
gsm_get_mnc(subscr->mcc, subscr->mnc));
|
2010-09-19 13:51:15 +00:00
|
|
|
} else
|
2010-05-09 16:01:49 +00:00
|
|
|
print(priv, " LAI: invalid\n");
|
|
|
|
if (subscr->key_seq != 7) {
|
2010-09-19 13:51:15 +00:00
|
|
|
print(priv, " Key: sequence %d ", subscr->key_seq);
|
2010-05-09 16:01:49 +00:00
|
|
|
for (i = 0; i < sizeof(subscr->key); i++)
|
|
|
|
print(priv, " %02x", subscr->key[i]);
|
|
|
|
print(priv, "\n");
|
|
|
|
}
|
|
|
|
if (subscr->plmn_valid)
|
2010-08-28 09:46:36 +00:00
|
|
|
print(priv, " Registered PLMN: MCC %s MNC %s (%s, %s)\n",
|
2010-06-26 13:56:01 +00:00
|
|
|
gsm_print_mcc(subscr->plmn_mcc),
|
|
|
|
gsm_print_mnc(subscr->plmn_mnc),
|
2010-05-09 16:01:49 +00:00
|
|
|
gsm_get_mcc(subscr->plmn_mcc),
|
|
|
|
gsm_get_mnc(subscr->plmn_mcc, subscr->plmn_mnc));
|
|
|
|
print(priv, " Access barred cells: %s\n",
|
|
|
|
(subscr->acc_barr) ? "yes" : "no");
|
|
|
|
print(priv, " Access classes:");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
if ((subscr->acc_class & (1 << i)))
|
|
|
|
print(priv, " C%d", i);
|
|
|
|
print(priv, "\n");
|
|
|
|
if (!llist_empty(&subscr->plmn_list)) {
|
|
|
|
print(priv, " List of preferred PLMNs:\n");
|
|
|
|
print(priv, " MCC |MNC\n");
|
|
|
|
print(priv, " -------+-------\n");
|
|
|
|
llist_for_each_entry(plmn_list, &subscr->plmn_list, entry)
|
2010-09-19 13:51:15 +00:00
|
|
|
print(priv, " %s |%s (%s, %s)\n",
|
2010-06-26 13:56:01 +00:00
|
|
|
gsm_print_mcc(plmn_list->mcc),
|
2010-09-19 13:51:15 +00:00
|
|
|
gsm_print_mnc(plmn_list->mnc),
|
|
|
|
gsm_get_mcc(plmn_list->mcc),
|
|
|
|
gsm_get_mnc(plmn_list->mcc, plmn_list->mnc));
|
2010-05-09 16:01:49 +00:00
|
|
|
}
|
|
|
|
if (!llist_empty(&subscr->plmn_na)) {
|
|
|
|
print(priv, " List of forbidden PLMNs:\n");
|
|
|
|
print(priv, " MCC |MNC |cause\n");
|
|
|
|
print(priv, " -------+-------+-------\n");
|
|
|
|
llist_for_each_entry(plmn_na, &subscr->plmn_na, entry)
|
2010-09-19 13:51:15 +00:00
|
|
|
print(priv, " %s |%s%s |#%d "
|
|
|
|
"(%s, %s)\n", gsm_print_mcc(plmn_na->mcc),
|
2010-06-26 13:56:01 +00:00
|
|
|
gsm_print_mnc(plmn_na->mnc),
|
|
|
|
((plmn_na->mnc & 0x00f) == 0x00f) ? " ":"",
|
2010-09-19 13:51:15 +00:00
|
|
|
plmn_na->cause, gsm_get_mcc(plmn_na->mcc),
|
|
|
|
gsm_get_mnc(plmn_na->mcc, plmn_na->mnc));
|
2010-05-09 16:01:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|