summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/atmodem/sim.c199
-rw-r--r--src/driver.h31
-rw-r--r--src/sim.c16
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,
diff --git a/src/sim.c b/src/sim.c
index acec7bb8..9c852929 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -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)