mirror of git://git.sysmocom.de/ofono
Move SPDI to network.c
This commit is contained in:
parent
f2440ebd82
commit
5ea1326b00
|
@ -66,6 +66,7 @@ struct network_registration_data {
|
|||
int signal_strength;
|
||||
char *spname;
|
||||
GSList *pnn_list;
|
||||
struct sim_spdi *spdi;
|
||||
};
|
||||
|
||||
static void operator_list_callback(const struct ofono_error *error, int total,
|
||||
|
@ -352,9 +353,12 @@ static char *get_operator_display_name(struct ofono_modem *modem)
|
|||
return name;
|
||||
}
|
||||
|
||||
home_or_spdi =
|
||||
(netreg->status == NETWORK_REGISTRATION_STATUS_REGISTERED) ||
|
||||
ofono_operator_in_spdi(modem, netreg->current_operator);
|
||||
if (netreg->status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||
home_or_spdi = TRUE;
|
||||
else
|
||||
home_or_spdi = sim_spdi_lookup(netreg->spdi,
|
||||
netreg->current_operator->mcc,
|
||||
netreg->current_operator->mnc);
|
||||
|
||||
if (home_or_spdi)
|
||||
if (netreg->flags & NETWORK_REGISTRATION_FLAG_HOME_SHOW_PLMN)
|
||||
|
@ -1136,6 +1140,43 @@ static void sim_pnn_read_cb(struct ofono_modem *modem, int ok,
|
|||
}
|
||||
}
|
||||
|
||||
static void sim_spdi_read_cb(struct ofono_modem *modem, int ok,
|
||||
enum ofono_sim_file_structure structure,
|
||||
int length, int record,
|
||||
const unsigned char *data,
|
||||
int record_length, void *userdata)
|
||||
{
|
||||
struct network_registration_data *netreg = modem->network_registration;
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
if (structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
|
||||
return;
|
||||
|
||||
netreg->spdi = sim_spdi_new(data, length);
|
||||
|
||||
if (!netreg->current_operator)
|
||||
return;
|
||||
|
||||
if (netreg->status == NETWORK_REGISTRATION_STATUS_ROAMING) {
|
||||
DBusConnection *conn = dbus_gsm_connection();
|
||||
const char *operator;
|
||||
|
||||
if (!sim_spdi_lookup(netreg->spdi,
|
||||
netreg->current_operator->mcc,
|
||||
netreg->current_operator->mnc))
|
||||
return;
|
||||
|
||||
operator = get_operator_display_name(modem);
|
||||
|
||||
dbus_gsm_signal_property_changed(conn, modem->path,
|
||||
NETWORK_REGISTRATION_INTERFACE,
|
||||
"Operator", DBUS_TYPE_STRING,
|
||||
&operator);
|
||||
}
|
||||
}
|
||||
|
||||
static void sim_spn_read_cb(struct ofono_modem *modem, int ok,
|
||||
enum ofono_sim_file_structure structure,
|
||||
int length, int record,
|
||||
|
@ -1143,8 +1184,6 @@ static void sim_spn_read_cb(struct ofono_modem *modem, int ok,
|
|||
int record_length, void *userdata)
|
||||
{
|
||||
struct network_registration_data *netreg = modem->network_registration;
|
||||
DBusConnection *conn = dbus_gsm_connection();
|
||||
const char *operator;
|
||||
unsigned char dcbyte;
|
||||
char *spn;
|
||||
|
||||
|
@ -1183,21 +1222,26 @@ static void sim_spn_read_cb(struct ofono_modem *modem, int ok,
|
|||
return;
|
||||
}
|
||||
|
||||
netreg->spname = spn;
|
||||
ofono_sim_read(modem, SIM_EFSPDI_FILEID, sim_spdi_read_cb, NULL);
|
||||
|
||||
if (dcbyte & SIM_EFSPN_DC_HOME_PLMN_BIT)
|
||||
netreg->flags |= NETWORK_REGISTRATION_FLAG_HOME_SHOW_PLMN;
|
||||
|
||||
if (!(dcbyte & SIM_EFSPN_DC_ROAMING_SPN_BIT))
|
||||
netreg->flags |= NETWORK_REGISTRATION_FLAG_ROAMING_SHOW_SPN;
|
||||
|
||||
if (!netreg->current_operator)
|
||||
return;
|
||||
if (netreg->current_operator) {
|
||||
DBusConnection *conn = dbus_gsm_connection();
|
||||
const char *operator;
|
||||
|
||||
operator = get_operator_display_name(modem);
|
||||
operator = get_operator_display_name(modem);
|
||||
|
||||
dbus_gsm_signal_property_changed(conn, modem->path,
|
||||
NETWORK_REGISTRATION_INTERFACE,
|
||||
"Operator", DBUS_TYPE_STRING,
|
||||
&operator);
|
||||
dbus_gsm_signal_property_changed(conn, modem->path,
|
||||
NETWORK_REGISTRATION_INTERFACE,
|
||||
"Operator", DBUS_TYPE_STRING,
|
||||
&operator);
|
||||
}
|
||||
}
|
||||
|
||||
static void sim_ready(struct ofono_modem *modem)
|
||||
|
|
126
src/sim.c
126
src/sim.c
|
@ -245,132 +245,6 @@ check:
|
|||
}
|
||||
}
|
||||
|
||||
struct sim_operator {
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
};
|
||||
|
||||
static void parse_mcc_mnc(struct sim_operator *oper, const guint8 *bcd)
|
||||
{
|
||||
char *mcc = oper->mcc;
|
||||
char *mnc = oper->mnc;
|
||||
guint8 digit;
|
||||
|
||||
digit = (bcd[0] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[0] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[1] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[2] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
digit = (bcd[2] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
digit = (bcd[1] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
}
|
||||
|
||||
static struct sim_operator *sim_operator_alloc(const guint8 *bcd)
|
||||
{
|
||||
struct sim_operator *spdi = g_new0(struct sim_operator, 1);
|
||||
|
||||
parse_mcc_mnc(spdi, bcd);
|
||||
|
||||
return spdi;
|
||||
}
|
||||
|
||||
static gint spdi_operator_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct sim_operator *opa = a;
|
||||
const struct sim_operator *opb = b;
|
||||
gint r;
|
||||
|
||||
if ((r = strcmp(opa->mcc, opb->mcc)))
|
||||
return r;
|
||||
|
||||
return strcmp(opa->mnc, opb->mnc);
|
||||
}
|
||||
|
||||
gboolean ofono_operator_in_spdi(struct ofono_modem *modem,
|
||||
const struct ofono_network_operator *op)
|
||||
{
|
||||
struct sim_manager_data *sim = modem->sim_manager;
|
||||
struct sim_operator spdi_op;
|
||||
|
||||
if (!sim)
|
||||
return FALSE;
|
||||
|
||||
g_strlcpy(spdi_op.mcc, op->mcc, sizeof(spdi_op.mcc));
|
||||
g_strlcpy(spdi_op.mnc, op->mnc, sizeof(spdi_op.mnc));
|
||||
|
||||
return g_slist_find_custom(sim->spdi,
|
||||
&spdi_op, spdi_operator_compare) != NULL;
|
||||
}
|
||||
|
||||
static void sim_spdi_read_cb(const struct ofono_error *error,
|
||||
const unsigned char *spdidata,
|
||||
int length, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = data;
|
||||
struct sim_manager_data *sim = modem->sim_manager;
|
||||
const guint8 *plmn_list;
|
||||
GSList *l;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length <= 5)
|
||||
return;
|
||||
|
||||
plmn_list = ber_tlv_find_by_tag(spdidata, 0x80, length, &length);
|
||||
if (!plmn_list) {
|
||||
ofono_debug("Couldn't parse the EF-SPDI contents as a TLV");
|
||||
return;
|
||||
}
|
||||
|
||||
for (length /= 3; length --; plmn_list += 3) {
|
||||
if ((plmn_list[0] & plmn_list[1] & plmn_list[2]) == 0xff)
|
||||
continue;
|
||||
|
||||
sim->spdi = g_slist_insert_sorted(sim->spdi,
|
||||
sim_operator_alloc(plmn_list),
|
||||
spdi_operator_compare);
|
||||
}
|
||||
|
||||
if (sim->spdi)
|
||||
for (l = sim->update_spn_notify; l; l = l->next)
|
||||
sim_spn_notify(modem, l->data);
|
||||
}
|
||||
|
||||
static void sim_spdi_info_cb(const struct ofono_error *error, int length,
|
||||
enum ofono_sim_file_structure structure,
|
||||
int dummy, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = data;
|
||||
struct sim_manager_data *sim = modem->sim_manager;
|
||||
|
||||
if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length <= 5 ||
|
||||
structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
|
||||
return;
|
||||
|
||||
sim->ops->read_file_transparent(modem, SIM_EFSPDI_FILEID, 0, length,
|
||||
sim_spdi_read_cb, modem);
|
||||
}
|
||||
|
||||
static gboolean sim_retrieve_spdi(void *user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct sim_manager_data *sim = modem->sim_manager;
|
||||
|
||||
sim->ops->read_file_info(modem, SIM_EFSPDI_FILEID,
|
||||
sim_spdi_info_cb, modem);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct opl_operator {
|
||||
struct sim_operator mcc_mnc;
|
||||
guint16 lac_tac_low;
|
||||
|
|
|
@ -30,8 +30,6 @@ typedef void (*ofono_sim_file_read_cb_t)(struct ofono_modem *modem, int ok,
|
|||
void ofono_sim_manager_init(struct ofono_modem *modem);
|
||||
void ofono_sim_manager_exit(struct ofono_modem *modem);
|
||||
|
||||
gboolean ofono_operator_in_spdi(struct ofono_modem *modem,
|
||||
const struct ofono_network_operator *op);
|
||||
const char *ofono_sim_get_imsi(struct ofono_modem *modem);
|
||||
|
||||
int ofono_sim_ready_notify_register(struct ofono_modem *modem,
|
||||
|
|
|
@ -27,9 +27,15 @@
|
|||
|
||||
#include <glib.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
|
||||
struct spdi_operator {
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
};
|
||||
|
||||
/* Parse ASN.1 Basic Encoding Rules TLVs per ISO/IEC 7816 */
|
||||
const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag,
|
||||
int in_len, int *out_len)
|
||||
|
@ -156,3 +162,89 @@ void sim_pnn_operator_free(struct sim_pnn_operator *oper)
|
|||
g_free(oper->shortname);
|
||||
g_free(oper->longname);
|
||||
}
|
||||
|
||||
static void parse_mcc_mnc(const guint8 *bcd, char *mcc, char *mnc)
|
||||
{
|
||||
guint8 digit;
|
||||
|
||||
digit = (bcd[0] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[0] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[1] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mcc ++ = '0' + digit;
|
||||
digit = (bcd[2] >> 0) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
digit = (bcd[2] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
digit = (bcd[1] >> 4) & 0xf;
|
||||
if (digit != 0xf)
|
||||
*mnc ++ = '0' + digit;
|
||||
}
|
||||
|
||||
static gint spdi_operator_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct spdi_operator *opa = a;
|
||||
const struct spdi_operator *opb = b;
|
||||
gint r;
|
||||
|
||||
if (r = strcmp(opa->mcc, opb->mcc))
|
||||
return r;
|
||||
|
||||
return strcmp(opa->mnc, opb->mnc);
|
||||
}
|
||||
|
||||
struct sim_spdi *sim_spdi_new(const guint8 *tlv, int length)
|
||||
{
|
||||
const guint8 *plmn_list;
|
||||
struct sim_spdi *spdi;
|
||||
struct spdi_operator *oper;
|
||||
int tlv_length;
|
||||
|
||||
if (length <= 5)
|
||||
return NULL;
|
||||
|
||||
plmn_list = ber_tlv_find_by_tag(tlv, 0x80, length, &tlv_length);
|
||||
|
||||
if (!plmn_list)
|
||||
return NULL;
|
||||
|
||||
spdi = g_new0(struct sim_spdi, 1);
|
||||
|
||||
for (tlv_length /= 3; tlv_length--; plmn_list += 3) {
|
||||
if ((plmn_list[0] & plmn_list[1] & plmn_list[2]) == 0xff)
|
||||
continue;
|
||||
|
||||
oper = g_new0(struct spdi_operator, 1);
|
||||
|
||||
parse_mcc_mnc(plmn_list, oper->mcc, oper->mnc);
|
||||
spdi->operators = g_slist_insert_sorted(spdi->operators, oper,
|
||||
spdi_operator_compare);
|
||||
}
|
||||
|
||||
return spdi;
|
||||
}
|
||||
|
||||
gboolean sim_spdi_lookup(struct sim_spdi *spdi,
|
||||
const char *mcc, const char *mnc)
|
||||
{
|
||||
struct spdi_operator spdi_op;
|
||||
|
||||
g_strlcpy(spdi_op.mcc, mcc, sizeof(spdi_op.mcc));
|
||||
g_strlcpy(spdi_op.mnc, mnc, sizeof(spdi_op.mnc));
|
||||
|
||||
return g_slist_find_custom(spdi->operators, &spdi_op,
|
||||
spdi_operator_compare) != NULL;
|
||||
}
|
||||
|
||||
void sim_spdi_free(struct sim_spdi *spdi)
|
||||
{
|
||||
g_slist_foreach(spdi->operators, (GFunc)g_free, NULL);
|
||||
g_slist_free(spdi->operators);
|
||||
g_free(spdi);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ struct sim_pnn_operator {
|
|||
char *info;
|
||||
};
|
||||
|
||||
struct sim_spdi {
|
||||
GSList *operators;
|
||||
};
|
||||
|
||||
void sim_pnn_operator_free(struct sim_pnn_operator *oper);
|
||||
|
||||
const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag,
|
||||
|
@ -45,3 +49,8 @@ const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag,
|
|||
char *sim_network_name_parse(const unsigned char *buffer, int length,
|
||||
gboolean *add_ci);
|
||||
struct sim_pnn_operator *sim_pnn_operator_parse(const guint8 *tlv, int length);
|
||||
|
||||
struct sim_spdi *sim_spdi_new(const guint8 *tlv, int length);
|
||||
gboolean sim_spdi_lookup(struct sim_spdi *spdi,
|
||||
const char *mcc, const char *mnc);
|
||||
void sim_spdi_free(struct sim_spdi *spdi);
|
||||
|
|
Loading…
Reference in New Issue