diff options
author | Andrzej Zaborowski <andrew.zaborowski@intel.com> | 2009-06-18 05:44:44 +0200 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2009-06-18 04:02:05 -0500 |
commit | 2b451eaeab59c255a850afbcc354bacd186700ba (patch) | |
tree | b45733e558ce55d5e59ca596eff12218c0f2ea64 | |
parent | 498759f2b6f68fd7c1326589a4c20176a266fa41 (diff) | |
download | ofono-2b451eaeab59c255a850afbcc354bacd186700ba.tar.bz2 |
Add record based file capability to sim_ops
Add capability to read / write / stat files on the SIM. This now
supports cyclic, linear fixed and transparent SIM files.
Parse GET RESPONSE result to find structure of the file (cyclic, linear
fixed, or transparent), the file size and the record length.
Add both read and update capability for binary and record-based files.
Implement writing sim files through AT.
-rw-r--r-- | drivers/atmodem/sim.c | 199 | ||||
-rw-r--r-- | src/driver.h | 31 | ||||
-rw-r--r-- | src/sim.c | 16 |
3 files changed, 210 insertions, 36 deletions
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c index a2aebb89..66e951ec 100644 --- a/drivers/atmodem/sim.c +++ b/drivers/atmodem/sim.c @@ -41,20 +41,22 @@ static const char *crsm_prefix[] = { "+CRSM:", NULL }; static const char *cnum_prefix[] = { "+CNUM:", NULL }; -static void at_crsm_len_cb(gboolean ok, GAtResult *result, gpointer user_data) +static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; GAtResultIter iter; - ofono_sim_file_len_cb_t cb = cbd->cb; + ofono_sim_file_info_cb_t cb = cbd->cb; struct ofono_error error; const guint8 *response; gint sw1, sw2, len; + int flen, rlen; + enum ofono_simfile_struct str; - dump_response("at_crsm_len_cb", ok, result); + dump_response("at_crsm_info_cb", ok, result); decode_at_error(&error, g_at_result_final_response(result)); if (!ok) { - cb(&error, -1, cbd->data); + cb(&error, -1, -1, -1, cbd->data); return; } @@ -63,29 +65,38 @@ static void at_crsm_len_cb(gboolean ok, GAtResult *result, gpointer user_data) if (!g_at_result_iter_next(&iter, "+CRSM:")) { DECLARE_FAILURE(e); - cb(&e, -1, cbd->data); + cb(&e, -1, -1, -1, cbd->data); return; } g_at_result_iter_next_number(&iter, &sw1); - g_at_result_iter_next_number(&iter, &len); + g_at_result_iter_next_number(&iter, &sw2); if (!g_at_result_iter_next_hexstring(&iter, &response, &len) || (sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) || - (sw1 == 0x90 && sw2 != 0x00) || len < 14) { + (sw1 == 0x90 && sw2 != 0x00) || + len < 14 || response[6] != 0x04 || + (response[13] == 0x01 && len < 15)) { DECLARE_FAILURE(e); - cb(&e, -1, cbd->data); + cb(&e, -1, -1, -1, cbd->data); return; } - ofono_debug("crsm_len_cb: %02x, %02x, %i", sw1, sw2, len); + ofono_debug("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len); + + flen = (response[2] << 8) | response[3]; + str = response[13]; + if (str == 0x01) + rlen = response[14]; + else + rlen = 0; - cb(&error, (response[2] << 8) | response[3], cbd->data); + cb(&error, flen, str, rlen, cbd->data); } -static void at_sim_read_file_len(struct ofono_modem *modem, int fileid, - ofono_sim_file_len_cb_t cb, +static void at_sim_read_info(struct ofono_modem *modem, int fileid, + ofono_sim_file_info_cb_t cb, void *data) { struct at_data *at = ofono_modem_userdata(modem); @@ -97,7 +108,7 @@ static void at_sim_read_file_len(struct ofono_modem *modem, int fileid, snprintf(buf, sizeof(buf), "AT+CRSM=192,%i,0,0,15", fileid); if (g_at_chat_send(at->parser, buf, crsm_prefix, - at_crsm_len_cb, cbd, g_free) > 0) + at_crsm_info_cb, cbd, g_free) > 0) return; error: @@ -106,11 +117,12 @@ error: { DECLARE_FAILURE(error); - cb(&error, -1, data); + cb(&error, -1, -1, -1, data); } } -static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data) +static void at_crsm_read_cb(gboolean ok, GAtResult *result, + gpointer user_data) { struct cb_data *cbd = user_data; GAtResultIter iter; @@ -119,7 +131,7 @@ static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data) const guint8 *response; gint sw1, sw2, len; - dump_response("at_crsm_cb", ok, result); + dump_response("at_crsm_read_cb", ok, result); decode_at_error(&error, g_at_result_final_response(result)); if (!ok) { @@ -147,14 +159,14 @@ static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data) return; } - ofono_debug("crsm_cb: %02x, %02x, %d", sw1, sw2, len); + ofono_debug("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len); cb(&error, response, len, cbd->data); } -static void at_sim_read_file(struct ofono_modem *modem, int fileid, int start, - int length, ofono_sim_read_cb_t cb, - void *data) +static void at_sim_read_binary(struct ofono_modem *modem, int fileid, + int start, int length, + ofono_sim_read_cb_t cb, void *data) { struct at_data *at = ofono_modem_userdata(modem); struct cb_data *cbd = cb_data_new(modem, cb, data); @@ -166,7 +178,34 @@ static void at_sim_read_file(struct ofono_modem *modem, int fileid, int start, snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid, start >> 8, start & 0xff, length); if (g_at_chat_send(at->parser, buf, crsm_prefix, - at_crsm_cb, cbd, g_free) > 0) + at_crsm_read_cb, cbd, g_free) > 0) + return; + +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, NULL, 0, data); + } +} + +static void at_sim_read_record(struct ofono_modem *modem, int fileid, + int record, int length, + ofono_sim_read_cb_t cb, void *data) +{ + struct at_data *at = ofono_modem_userdata(modem); + struct cb_data *cbd = cb_data_new(modem, cb, data); + char buf[64]; + + if (!cbd) + goto error; + + snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid, + record + 1, length); + if (g_at_chat_send(at->parser, buf, crsm_prefix, + at_crsm_read_cb, cbd, g_free) > 0) return; error: @@ -179,6 +218,117 @@ error: } } +static void at_crsm_update_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + GAtResultIter iter; + ofono_generic_cb_t cb = cbd->cb; + struct ofono_error error; + gint sw1, sw2; + + dump_response("at_crsm_update_cb", ok, result); + decode_at_error(&error, g_at_result_final_response(result)); + + if (!ok) { + cb(&error, cbd->data); + return; + } + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CRSM:")) { + DECLARE_FAILURE(e); + + cb(&e, cbd->data); + return; + } + + g_at_result_iter_next_number(&iter, &sw1); + g_at_result_iter_next_number(&iter, &sw2); + if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) || + (sw1 == 0x90 && sw2 != 0x00)) { + DECLARE_FAILURE(e); + + cb(&e, cbd->data); + return; + } + + ofono_debug("crsm_update_cb: %02x, %02x", sw1, sw2); + + cb(&error, cbd->data); +} + +static void at_sim_update_binary(struct ofono_modem *modem, int fileid, + int start, int length, + const unsigned char *value, + ofono_generic_cb_t cb, void *data) +{ + struct at_data *at = ofono_modem_userdata(modem); + struct cb_data *cbd = cb_data_new(modem, cb, data); + char *buf = g_try_new(char, 36 + length * 2); + int len, ret; + + if (!cbd || !buf) + goto error; + + len = sprintf(buf, "AT+CRSM=214,%i,%i,%i,%i,", fileid, + start >> 8, start & 0xff, length); + for (; length; length--) + len += sprintf(buf + len, "%02hhx", *value++); + ret = g_at_chat_send(at->parser, buf, crsm_prefix, + at_crsm_update_cb, cbd, g_free); + + g_free(buf); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, data); + } +} + +static void at_sim_update_record(struct ofono_modem *modem, int fileid, + int record, int length, + const unsigned char *value, + ofono_generic_cb_t cb, void *data) +{ + struct at_data *at = ofono_modem_userdata(modem); + struct cb_data *cbd = cb_data_new(modem, cb, data); + char *buf = g_try_new(char, 36 + length * 2); + int len, ret; + + if (!cbd || !buf) + goto error; + + len = sprintf(buf, "AT+CRSM=220,%i,%i,4,%i,", fileid, + record + 1, length); + for (; length; length--) + len += sprintf(buf + len, "%02hhx", *value++); + ret = g_at_chat_send(at->parser, buf, crsm_prefix, + at_crsm_update_cb, cbd, g_free); + + g_free(buf); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, data); + } +} + static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; @@ -317,8 +467,11 @@ error: } static struct ofono_sim_ops ops = { - .read_file_len = at_sim_read_file_len, - .read_file = at_sim_read_file, + .read_file_info = at_sim_read_info, + .read_file_transparent = at_sim_read_binary, + .read_file_linear = at_sim_read_record, + .write_file_transparent = at_sim_update_binary, + .write_file_linear = at_sim_update_record, .read_imsi = at_read_imsi, .read_own_numbers = at_read_msisdn, }; diff --git a/src/driver.h b/src/driver.h index 3a690f0f..842bc107 100644 --- a/src/driver.h +++ b/src/driver.h @@ -102,6 +102,13 @@ struct ofono_own_number { int itc; }; +/* 51.011 Section 9.3 */ +enum ofono_simfile_struct { + OFONO_SIM_FILE_TRANSPARENT = 0, + OFONO_SIM_FILE_FIXED = 1, + OFONO_SIM_FILE_CYCLIC = 3 +}; + /* Notification functions, the integer values here should map to * values obtained from the modem. The enumerations are the same * as the values for the fields found in 3GPP TS 27.007 @@ -160,8 +167,10 @@ typedef void (*ofono_call_meter_puct_query_cb_t)(const struct ofono_error *error typedef void (*ofono_call_barring_cb_t)(const struct ofono_error *error, int status, void *data); -typedef void (*ofono_sim_file_len_cb_t)(const struct ofono_error *error, - int length, void *data); +typedef void (*ofono_sim_file_info_cb_t)(const struct ofono_error *error, + int filelength, + enum ofono_simfile_struct structure, + int recordlength, void *data); typedef void (*ofono_sim_read_cb_t)(const struct ofono_error *error, const unsigned char *sdata, int length, @@ -367,10 +376,20 @@ int ofono_call_barring_register(struct ofono_modem *modem, void ofono_call_barring_unregister(struct ofono_modem *modem); struct ofono_sim_ops { - void (*read_file_len)(struct ofono_modem *modem, int fileid, - ofono_sim_file_len_cb_t cb, void *data); - void (*read_file)(struct ofono_modem *modem, int fileid, int start, - int length, ofono_sim_read_cb_t cb, void *data); + void (*read_file_info)(struct ofono_modem *modem, int fileid, + ofono_sim_file_info_cb_t cb, void *data); + void (*read_file_transparent)(struct ofono_modem *modem, int fileid, + int start, int length, + ofono_sim_read_cb_t cb, void *data); + void (*read_file_linear)(struct ofono_modem *modem, int fileid, + int record, int length, + ofono_sim_read_cb_t cb, void *data); + void (*write_file_transparent)(struct ofono_modem *modem, int fileid, + int start, int length, const unsigned char *value, + ofono_generic_cb_t cb, void *data); + void (*write_file_linear)(struct ofono_modem *modem, int fileid, + int record, int length, const unsigned char *value, + ofono_generic_cb_t cb, void *data); void (*read_imsi)(struct ofono_modem *modem, ofono_imsi_cb_t cb, void *data); void (*read_own_numbers)(struct ofono_modem *modem, @@ -237,16 +237,18 @@ static void sim_spn_read_cb(const struct ofono_error *error, sim_spn_notify(modem, l->data); } -static void sim_spn_len_cb(const struct ofono_error *error, - int length, void *data) +static void sim_spn_info_cb(const struct ofono_error *error, + int length, enum ofono_simfile_struct 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 <= 1) + if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length <= 1 || + structure != OFONO_SIM_FILE_TRANSPARENT) return; - sim->ops->read_file(modem, SIM_EFSPN_FILEID, 0, length, + sim->ops->read_file_transparent(modem, SIM_EFSPN_FILEID, 0, length, sim_spn_read_cb, modem); } @@ -255,8 +257,8 @@ static gboolean sim_retrieve_spn(void *user_data) struct ofono_modem *modem = user_data; struct sim_manager_data *sim = modem->sim_manager; - sim->ops->read_file_len(modem, SIM_EFSPN_FILEID, - sim_spn_len_cb, modem); + sim->ops->read_file_info(modem, SIM_EFSPN_FILEID, + sim_spn_info_cb, modem); return FALSE; } @@ -341,7 +343,7 @@ static void initialize_sim_manager(struct ofono_modem *modem) modem_add_interface(modem, SIM_MANAGER_INTERFACE); - if (modem->sim_manager->ops->read_file) + if (modem->sim_manager->ops->read_file_transparent) g_timeout_add(0, sim_retrieve_spn, modem); if (modem->sim_manager->ops->read_imsi) |