diff options
author | Denis Kenzior <denkenz@gmail.com> | 2009-07-13 18:30:17 -0500 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2009-07-14 15:45:05 -0500 |
commit | 0fa689721347cc5b97b5b84c1f6495983a3bff61 (patch) | |
tree | f81c65a56c0e6ff3c1f247cf03b36e7dc2b58911 /src | |
parent | 0fd50806304018485f64f27caf051444904a7ae0 (diff) | |
download | ofono-0fa689721347cc5b97b5b84c1f6495983a3bff61.tar.bz2 |
Refactor OPL code
Diffstat (limited to 'src')
-rw-r--r-- | src/network.c | 48 | ||||
-rw-r--r-- | src/sim.c | 133 | ||||
-rw-r--r-- | src/sim.h | 3 | ||||
-rw-r--r-- | src/simutil.c | 209 | ||||
-rw-r--r-- | src/simutil.h | 30 |
5 files changed, 221 insertions, 202 deletions
diff --git a/src/network.c b/src/network.c index 570866ec..186b5eec 100644 --- a/src/network.c +++ b/src/network.c @@ -65,8 +65,8 @@ struct network_registration_data { DBusMessage *pending; int signal_strength; char *spname; - GSList *pnn_list; struct sim_spdi *spdi; + struct sim_eons *eons; }; static void operator_list_callback(const struct ofono_error *error, int total, @@ -571,8 +571,11 @@ static void network_registration_destroy(gpointer userdata) g_slist_free(data->operator_list); - g_slist_foreach(data->pnn_list, (GFunc)sim_pnn_operator_free, NULL); - g_slist_free(data->pnn_list); + if (data->eons) + sim_eons_free(data->eons); + + if (data->spdi) + sim_spdi_free(data->spdi); if (data->spname) g_free(data->spname); @@ -1106,6 +1109,34 @@ static void signal_strength_callback(const struct ofono_error *error, ofono_signal_strength_notify(modem, strength); } +static void sim_opl_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; + int total = length / record_length; + + if (!ok) + return; + + if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED) + return; + + if (length < 8 || record_length < 8 || length < record_length) + return; + + /* If we don't have PNN, ignore this completely */ + if (!netreg->eons) + return; + + sim_eons_add_pnn_record(netreg->eons, record, data, record_length); + + if (record == total) + sim_eons_optimize(netreg->eons); +} + static void sim_pnn_read_cb(struct ofono_modem *modem, int ok, enum ofono_sim_file_structure structure, int length, int record, @@ -1113,7 +1144,6 @@ static void sim_pnn_read_cb(struct ofono_modem *modem, int ok, int record_length, void *userdata) { struct network_registration_data *netreg = modem->network_registration; - struct sim_pnn_operator *oper; int total = length / record_length; if (!ok) @@ -1125,19 +1155,17 @@ static void sim_pnn_read_cb(struct ofono_modem *modem, int ok, if (length < 3 || record_length < 3 || length < record_length) return; - oper = sim_pnn_operator_parse(data, record_length); + if (!netreg->eons) + netreg->eons = sim_eons_new(total); - if (oper) - netreg->pnn_list = g_slist_prepend(netreg->pnn_list, oper); + sim_eons_add_pnn_record(netreg->eons, record, data, record_length); /* If PNN is not present then OPL is not useful, don't * retrieve it. If OPL is not there then PNN[1] will * still be used for the HPLMN and/or EHPLMN, if PNN * is present. */ - if (record == total && g_slist_length(netreg->pnn_list) > 0) { - netreg->pnn_list = g_slist_reverse(netreg->pnn_list); + if (record == total && !sim_eons_pnn_is_empty(netreg->eons)) ofono_sim_read(modem, SIM_EFOPL_FILEID, sim_opl_read_cb, NULL); - } } static void sim_spdi_read_cb(struct ofono_modem *modem, int ok, @@ -245,139 +245,6 @@ check: } } -struct opl_operator { - struct sim_operator mcc_mnc; - guint16 lac_tac_low; - guint16 lac_tac_high; - guint8 id; -}; - -static struct opl_operator *opl_operator_alloc(const guint8 *record) -{ - struct opl_operator *oper = g_new0(struct opl_operator, 1); - - parse_mcc_mnc(&oper->mcc_mnc, record); - record += 3; - - oper->lac_tac_low = (record[0] << 8) | record[1]; - record += 2; - oper->lac_tac_high = (record[0] << 8) | record[1]; - record += 2; - - oper->id = record[0]; - if (!oper->id) { - /* TODO: name to be taken from other sources, see TS 22.101 */ - } - - return oper; -} - -static gint opl_operator_compare(gconstpointer a, gconstpointer b) -{ - const struct opl_operator *opa = a; - const struct sim_operator *opb = b; - int i; - - for (i = 0; opb->mcc[i] | opa->mcc_mnc.mcc[i]; i ++) - if (opb->mcc[i] != opa->mcc_mnc.mcc[i] && - !(opa->mcc_mnc.mcc[i] == '0' + 0xd && - opb->mcc[i])) - return opa->mcc_mnc.mcc[i] - opb->mcc[i]; - for (i = 0; opb->mnc[i] | opa->mcc_mnc.mnc[i]; i ++) - if (opb->mnc[i] != opa->mcc_mnc.mnc[i] && - !(opa->mcc_mnc.mnc[i] == '0' + 0xd && - opb->mnc[i])) - return opa->mcc_mnc.mnc[i] - opb->mnc[i]; - - if (opa->lac_tac_low > 0x0000 || opa->lac_tac_high < 0xfffe) - return 1; - - return 0; -} - -static void sim_opl_read_cb(const struct ofono_error *error, - const unsigned char *sdata, int length, void *data) -{ - struct ofono_modem *modem = data; - struct sim_manager_data *sim = modem->sim_manager; - struct opl_operator *oper; - - if (error->type != OFONO_ERROR_TYPE_NO_ERROR) - goto skip; - - if (length < sim->opl_size) - goto skip; - - oper = opl_operator_alloc(sdata); - if (oper->id > sim->pnn_num) { - g_free(oper); - goto skip; - } - - sim->opl = g_slist_prepend(sim->opl, oper); - -skip: - sim->opl_current ++; - if (sim->opl_current < sim->opl_num) - sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID, - sim->opl_current, - sim->opl_size, - sim_opl_read_cb, modem); - else - /* All records retrieved */ - if (sim->opl) - sim->opl = g_slist_reverse(sim->opl); -} - -static void sim_opl_info_cb(const struct ofono_error *error, int length, - enum ofono_sim_file_structure structure, - int record_length, void *data) -{ - struct ofono_modem *modem = data; - struct sim_manager_data *sim = modem->sim_manager; - - if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length < 8 || - record_length < 8 || - structure != OFONO_SIM_FILE_STRUCTURE_FIXED) - return; - - sim->opl_current = 0; - sim->opl_size = record_length; - sim->opl_num = length / record_length; - sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID, 0, - record_length, sim_opl_read_cb, modem); -} - -static gboolean sim_retrieve_opl(void *user_data) -{ - struct ofono_modem *modem = user_data; - struct sim_manager_data *sim = modem->sim_manager; - - sim->ops->read_file_info(modem, SIM_EFOPL_FILEID, - sim_opl_info_cb, modem); - - return FALSE; -} - -const char *ofono_operator_name_sim_override(struct ofono_modem *modem, - const char *mcc, const char *mnc) -{ - struct sim_manager_data *sim = modem->sim_manager; - struct sim_operator op; - GSList *l; - const struct opl_operator *opl_op; - - g_strlcpy(op.mcc, mcc, sizeof(op.mcc)); - g_strlcpy(op.mnc, mnc, sizeof(op.mnc)); - - l = g_slist_find_custom(sim->opl, &op, opl_operator_compare); - if (!l) - return NULL; - opl_op = l->data; - - return sim->pnn[opl_op->id - 1].longname; -} - static void sim_ready(struct ofono_modem *modem) { ofono_sim_read(modem, SIM_EFMSISDN_FILEID, sim_msisdn_read_cb, NULL); @@ -37,9 +37,6 @@ int ofono_sim_ready_notify_register(struct ofono_modem *modem, void ofono_sim_ready_notify_unregister(struct ofono_modem *modem, ofono_sim_ready_notify_cb_t cb); -const char *ofono_operator_name_sim_override(struct ofono_modem *modem, - const char *mcc, - const char *mnc); int ofono_sim_get_ready(struct ofono_modem *modem); void ofono_sim_set_ready(struct ofono_modem *modem); diff --git a/src/simutil.c b/src/simutil.c index 465b8f34..6830faca 100644 --- a/src/simutil.c +++ b/src/simutil.c @@ -31,14 +31,30 @@ #include "simutil.h" #include "util.h" +struct pnn_operator { + char *longname; + gboolean long_ci; + char *shortname; + gboolean short_ci; + char *info; +}; + struct spdi_operator { char mcc[OFONO_MAX_MCC_LENGTH + 1]; char mnc[OFONO_MAX_MNC_LENGTH + 1]; }; +struct opl_operator { + char mcc[OFONO_MAX_MCC_LENGTH + 1]; + char mnc[OFONO_MAX_MNC_LENGTH + 1]; + guint16 lac_tac_low; + guint16 lac_tac_high; + guint8 id; +}; + /* 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) +static const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag, + int in_len, int *out_len) { guint8 tag; int len; @@ -74,8 +90,8 @@ const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag, return NULL; } -char *sim_network_name_parse(const unsigned char *buffer, int length, - gboolean *add_ci) +static char *sim_network_name_parse(const unsigned char *buffer, int length, + gboolean *add_ci) { char *ret = NULL; unsigned char *endp; @@ -125,44 +141,6 @@ char *sim_network_name_parse(const unsigned char *buffer, int length, return ret; } -struct sim_pnn_operator *sim_pnn_operator_parse(const guint8 *tlv, int length) -{ - const char *name; - int namelength; - gboolean add_ci; - struct sim_pnn_operator *oper; - - name = ber_tlv_find_by_tag(tlv, 0x43, length, &namelength); - - if (!name || !namelength) - return NULL; - - oper = g_new0(struct sim_pnn_operator, 1); - - oper->longname = sim_network_name_parse(name, namelength, - &oper->long_ci); - - name = ber_tlv_find_by_tag(tlv, 0x45, length, &namelength); - - if (name && namelength) - oper->shortname = sim_network_name_parse(name, namelength, - &oper->short_ci); - - name = ber_tlv_find_by_tag(tlv, 0x80, length, &namelength); - - if (name && namelength) - oper->info = sim_string_to_utf8(name, namelength); - - return oper; -} - -void sim_pnn_operator_free(struct sim_pnn_operator *oper) -{ - g_free(oper->info); - g_free(oper->shortname); - g_free(oper->longname); -} - static void parse_mcc_mnc(const guint8 *bcd, char *mcc, char *mnc) { static const char digit_lut[] = "0123456789*#abd\0"; @@ -248,3 +226,150 @@ void sim_spdi_free(struct sim_spdi *spdi) g_slist_free(spdi->operators); g_free(spdi); } + +static void pnn_operator_free(struct pnn_operator *oper) +{ + g_free(oper->info); + g_free(oper->shortname); + g_free(oper->longname); +} + +struct sim_eons *sim_eons_new(int pnn_records) +{ + struct sim_eons *eons = g_new0(struct sim_eons, 1); + + eons->pnn_list = g_new0(struct pnn_operator, pnn_records); + eons->pnn_max = pnn_records; + + return eons; +} + +gboolean sim_eons_pnn_is_empty(struct sim_eons *eons) +{ + return !eons->pnn_valid; +} + +void sim_eons_add_pnn_record(struct sim_eons *eons, int record, + const guint8 *tlv, int length) +{ + const char *name; + int namelength; + gboolean add_ci; + struct pnn_operator *oper = &eons->pnn_list[record-1]; + + name = ber_tlv_find_by_tag(tlv, 0x43, length, &namelength); + + if (!name || !namelength) + return; + + oper->longname = sim_network_name_parse(name, namelength, + &oper->long_ci); + + name = ber_tlv_find_by_tag(tlv, 0x45, length, &namelength); + + if (name && namelength) + oper->shortname = sim_network_name_parse(name, namelength, + &oper->short_ci); + + name = ber_tlv_find_by_tag(tlv, 0x80, length, &namelength); + + if (name && namelength) + oper->info = sim_string_to_utf8(name, namelength); + + eons->pnn_valid = TRUE; +} + +static struct opl_operator *opl_operator_alloc(const guint8 *record) +{ + struct opl_operator *oper = g_new0(struct opl_operator, 1); + + parse_mcc_mnc(record, oper->mcc, oper->mnc); + record += 3; + + oper->lac_tac_low = (record[0] << 8) | record[1]; + record += 2; + oper->lac_tac_high = (record[0] << 8) | record[1]; + record += 2; + + oper->id = record[0]; + + return oper; +} + +void sim_eons_add_opl_record(struct sim_eons *eons, + const guint8 *tlv, int length) +{ + struct opl_operator *oper; + + oper = opl_operator_alloc(tlv); + + if (oper->id > eons->pnn_max) { + g_free(oper); + return; + } + + eons->opl_list = g_slist_prepend(eons->opl_list, oper); +} + +void sim_eons_optimize(struct sim_eons *eons) +{ + eons->opl_list = g_slist_reverse(eons->opl_list); +} + +void sim_eons_free(struct sim_eons *eons) +{ + int i; + + for (i = 0; i < eons->pnn_max; i++) + pnn_operator_free(eons->pnn_list + i); + + g_free(eons->pnn_list); + + g_slist_foreach(eons->opl_list, (GFunc)g_free, NULL); + g_slist_free(eons->opl_list); + + g_free(eons); +} + +static gint opl_operator_compare(gconstpointer a, gconstpointer b) +{ +} + +const char *sim_eons_lookup(struct sim_eons *eons, + const char *mcc, const char *mnc, guint16 lac) +{ + GSList *l; + const struct opl_operator *opl; + int i; + + for (l = eons->opl_list; l; l = l->next) { + opl = l->data; + + for (i = 0; i < OFONO_MAX_MCC_LENGTH; i++) + if (mcc[i] != opl->mcc[i] && + !(opl->mcc[i] == 'd' && mcc[i])) + continue; + + for (i = 0; i < OFONO_MAX_MNC_LENGTH; i++) + if (mnc[i] != opl->mnc[i] && + !(opl->mnc[i] == 'd' && mnc[i])) + continue; + + if (opl->lac_tac_low == 0 && opl->lac_tac_high == 0xfffe) + break; + + if ((lac >= opl->lac_tac_low) && (lac <= opl->lac_tac_high)) + break; + } + + if (!l) + return NULL; + + opl = l->data; + + /* 0 is not a valid record id */ + if (opl->id == 0) + return NULL; + + return eons->pnn_list[opl->id - 1].longname; +} diff --git a/src/simutil.h b/src/simutil.h index eff2d99e..49677d72 100644 --- a/src/simutil.h +++ b/src/simutil.h @@ -30,25 +30,27 @@ enum sim_fileid { #define SIM_EFSPN_DC_HOME_PLMN_BIT 0x1 #define SIM_EFSPN_DC_ROAMING_SPN_BIT 0x2 -struct sim_pnn_operator { - char *longname; - gboolean long_ci; - char *shortname; - gboolean short_ci; - char *info; -}; - struct sim_spdi { GSList *operators; }; -void sim_pnn_operator_free(struct sim_pnn_operator *oper); +struct sim_eons { + struct pnn_operator *pnn_list; + GSList *opl_list; + gboolean pnn_valid; + int pnn_max; +}; -const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag, - int in_len, int *out_len); -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_eons *sim_eons_new(int pnn_records); +void sim_eons_add_pnn_record(struct sim_eons *eons, int record, + const guint8 *tlv, int length); +gboolean sim_eons_pnn_is_empty(struct sim_eons *eons); +void sim_eons_add_opl_record(struct sim_eons *eons, + const guint8 *tlv, int length); +void sim_eons_optimize(struct sim_eons *eons); +const char *sim_eons_lookup(struct sim_eons *eons, const char *mcc, + const char *mnc, guint16 lac); +void sim_eons_free(struct sim_eons *eons); struct sim_spdi *sim_spdi_new(const guint8 *tlv, int length); gboolean sim_spdi_lookup(struct sim_spdi *spdi, |