Move SPDI to network.c

This commit is contained in:
Denis Kenzior 2009-07-13 16:12:22 -05:00
parent f2440ebd82
commit 5ea1326b00
5 changed files with 157 additions and 140 deletions

View File

@ -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
View File

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

View File

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

View File

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

View File

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