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.
This commit is contained in:
Andrzej Zaborowski 2009-06-18 05:44:44 +02:00 committed by Denis Kenzior
parent 498759f2b6
commit 2b451eaeab
3 changed files with 210 additions and 36 deletions

View File

@ -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);
cb(&error, (response[2] << 8) | response[3], cbd->data);
flen = (response[2] << 8) | response[3];
str = response[13];
if (str == 0x01)
rlen = response[14];
else
rlen = 0;
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,7 @@ 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:
@ -179,6 +191,144 @@ error:
}
}
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:
if (cbd)
g_free(cbd);
{
DECLARE_FAILURE(error);
cb(&error, NULL, 0, data);
}
}
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,
};

View File

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

View File

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