* [sim-ready-nofify-v5 PATCH 0/3] ofono_sim_ready_notify
@ 2011-02-08 12:32 Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 1/3] sim: add ofono_sim_ready_notify Pekka.Pessi
0 siblings, 1 reply; 6+ messages in thread
From: Pekka.Pessi @ 2011-02-08 12:32 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 403 bytes --]
Hi all,
The missing bitwise-not has been added to the sim, and the patches has
been rebased to current master.
A call to ofono_sim_ready_notify() is now always expected after call to
query_passwd_state.
When ofono_sim_ready_notify() is invoked, it checks that the call is
expected and if needed, retries the query_passwd_state. Otherwise it
proceeds with sim initialization.
--Pekka
^ permalink raw reply [flat|nested] 6+ messages in thread
* [sim-ready-nofify-v5 PATCH 1/3] sim: add ofono_sim_ready_notify
2011-02-08 12:32 [sim-ready-nofify-v5 PATCH 0/3] ofono_sim_ready_notify Pekka.Pessi
@ 2011-02-08 12:32 ` Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Pekka.Pessi
0 siblings, 1 reply; 6+ messages in thread
From: Pekka.Pessi @ 2011-02-08 12:32 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3455 bytes --]
From: Pekka Pessi <Pekka.Pessi@nokia.com>
The sim atom waits for ofono_sim_ready_notify() after the callback
to query_passwd_state.
Upon call to ofono_sim_ready_notify(), SIM atom either continues
initialization or rechecks if the SIM still requires a pin code.
Based on patches by Kristen Accardi and Denis Kenzior.
---
include/sim.h | 1 +
src/sim.c | 35 +++++++++++++++++++++++++++++------
2 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/include/sim.h b/include/sim.h
index 412ae44..b33cf8c 100644
--- a/include/sim.h
+++ b/include/sim.h
@@ -196,6 +196,7 @@ void ofono_sim_remove_state_watch(struct ofono_sim *sim, unsigned int id);
enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim);
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted);
+void ofono_sim_ready_notify(struct ofono_sim *sim);
struct ofono_sim_context *ofono_sim_context_create(struct ofono_sim *sim);
void ofono_sim_context_free(struct ofono_sim_context *context);
diff --git a/src/sim.c b/src/sim.c
index 3350166..818d813 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -45,6 +45,8 @@
#include "simfs.h"
#include "stkutil.h"
+#define SIM_FLAG_WAIT_FOR_READY (1 << 0)
+
static GSList *g_drivers = NULL;
static void sim_own_numbers_update(struct ofono_sim *sim);
@@ -76,6 +78,7 @@ struct ofono_sim {
unsigned char efsst_length;
gboolean fixed_dialing;
gboolean barred_dialing;
+ guint flags;
char *imsi;
char mcc[OFONO_MAX_MCC_LENGTH + 1];
@@ -1621,6 +1624,8 @@ static void sim_efphase_read_cb(int ok, int length, int record,
static void sim_initialize_after_pin(struct ofono_sim *sim)
{
+ sim->flags &= ~SIM_FLAG_WAIT_FOR_READY;
+
ofono_sim_read(sim->context, SIM_EFPHASE_FILEID,
OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
sim_efphase_read_cb, sim);
@@ -1647,10 +1652,11 @@ static void sim_pin_query_cb(const struct ofono_error *error,
const char *path = __ofono_atom_get_path(sim->atom);
const char *pin_name;
+ sim->flags |= SIM_FLAG_WAIT_FOR_READY;
+
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
ofono_error("Querying PIN authentication state failed");
-
- goto checkdone;
+ return;
}
if (sim->pin_type != pin_type) {
@@ -1671,10 +1677,6 @@ static void sim_pin_query_cb(const struct ofono_error *error,
}
sim_pin_retries_check(sim);
-
-checkdone:
- if (pin_type == OFONO_SIM_PASSWORD_NONE)
- sim_initialize_after_pin(sim);
}
static void sim_pin_check(struct ofono_sim *sim)
@@ -1687,6 +1689,25 @@ static void sim_pin_check(struct ofono_sim *sim)
sim->driver->query_passwd_state(sim, sim_pin_query_cb, sim);
}
+void ofono_sim_ready_notify(struct ofono_sim *sim)
+{
+ DBG("");
+
+ if (sim == NULL)
+ return;
+
+ if (sim->state != OFONO_SIM_STATE_INSERTED)
+ return;
+
+ if (!(sim->flags & SIM_FLAG_WAIT_FOR_READY))
+ return;
+
+ if (sim->pin_type == OFONO_SIM_PASSWORD_NONE)
+ sim_initialize_after_pin(sim);
+ else
+ sim_pin_check(sim);
+}
+
static void sim_efli_read_cb(int ok, int length, int record,
const unsigned char *data,
int record_length, void *userdata)
@@ -2146,6 +2167,8 @@ static void sim_free_state(struct ofono_sim *sim)
sim->fixed_dialing = FALSE;
sim->barred_dialing = FALSE;
+
+ sim->flags = 0;
}
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 1/3] sim: add ofono_sim_ready_notify Pekka.Pessi
@ 2011-02-08 12:32 ` Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 3/3] isimodem/sim: added PIN and SIM state handling Pekka.Pessi
2011-02-09 22:09 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Denis Kenzior
0 siblings, 2 replies; 6+ messages in thread
From: Pekka.Pessi @ 2011-02-08 12:32 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 7533 bytes --]
From: Pekka Pessi <Pekka.Pessi@nokia.com>
Schedule a call to ofono_sim_ready_notify after pin code query returns
SIM READY.
Vendor quirks:
- IFX: register unsolicated +XSIM result code
- MBM: register unsolicated *EPEV result code
---
drivers/atmodem/sim.c | 166 ++++++++++++++++++++++++++++++++++--------------
1 files changed, 117 insertions(+), 49 deletions(-)
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index d9c0d8d..666edbe 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -46,10 +46,14 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define READY_TIMEOUT 5000
+
struct sim_data {
GAtChat *chat;
unsigned int vendor;
guint ready_id;
+ guint ready_source;
+ ofono_bool_t ready;
};
static const char *crsm_prefix[] = { "+CRSM:", NULL };
@@ -679,10 +683,55 @@ static void at_pin_retries_query(struct ofono_sim *sim,
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
+static void ready_unregister_and_notify(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ DBG("");
+
+ if (sd->ready_source > 0) {
+ g_source_remove(sd->ready_source);
+ sd->ready_source = 0;
+ }
+
+ ofono_sim_ready_notify(sim);
+}
+
+static gboolean ready_timeout(gpointer user_data)
+{
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ DBG("");
+
+ sd->ready_source = 0;
+
+ ofono_sim_ready_notify(sim);
+
+ return FALSE;
+}
+
+static void at_wait_for_ready(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ guint timeout;
+
+ if (sd->ready_source > 0)
+ return;
+
+ if (!sd->ready && sd->ready_id > 0)
+ timeout = READY_TIMEOUT;
+ else
+ timeout = 0;
+
+ sd->ready_source = g_timeout_add(timeout, ready_timeout, sim);
+}
+
static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
- struct sim_data *sd = ofono_sim_get_data(cbd->user);
+ struct ofono_sim *sim = cbd->user;
+ struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
ofono_sim_passwd_cb_t cb = cbd->cb;
struct ofono_error error;
@@ -729,6 +778,11 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
+ if (pin_type == OFONO_SIM_PASSWORD_NONE)
+ at_wait_for_ready(sim);
+ else
+ sd->ready = FALSE;
+
DBG("crsm_pin_cb: %s", pin_required);
cb(&error, pin_type, cbd->data);
@@ -753,13 +807,13 @@ static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
static void at_xsim_notify(GAtResult *result, gpointer user_data)
{
- struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
- ofono_sim_lock_unlock_cb_t cb = cbd->cb;
- struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
int state;
+ DBG("");
+
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XSIM:"))
@@ -776,65 +830,40 @@ static void at_xsim_notify(GAtResult *result, gpointer user_data)
return;
}
- cb(&error, cbd->data);
+ sd->ready = TRUE;
- g_at_chat_unregister(sd->chat, sd->ready_id);
- sd->ready_id = 0;
+ if (sd->ready_source > 0)
+ ready_unregister_and_notify(sim);
}
static void at_epev_notify(GAtResult *result, gpointer user_data)
{
- struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
- ofono_sim_lock_unlock_cb_t cb = cbd->cb;
- struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
- cb(&error, cbd->data);
+ DBG("");
- g_at_chat_unregister(sd->chat, sd->ready_id);
- sd->ready_id = 0;
+ sd->ready = TRUE;
+
+ if (sd->ready_source > 0)
+ ready_unregister_and_notify(sim);
}
static void at_pin_send_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
+ struct ofono_sim *sim = cbd->user;
+ struct sim_data *sd = ofono_sim_get_data(sim);
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error;
- decode_at_error(&error, g_at_result_final_response(result));
+ if (ok && sd->ready_id)
+ at_wait_for_ready(sim);
- if (!ok)
- goto done;
-
- switch (sd->vendor) {
- case OFONO_VENDOR_IFX:
- /*
- * On the IFX modem, AT+CPIN? can return READY too
- * early and so use +XSIM notification to detect
- * the ready state of the SIM.
- */
- sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
- at_xsim_notify,
- FALSE, cbd, g_free);
- return;
- case OFONO_VENDOR_MBM:
- /*
- * On the MBM modem, AT+CPIN? keeps returning SIM PIN
- * for a moment after successful AT+CPIN="..", but then
- * sends *EPEV when that changes.
- */
- sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
- at_epev_notify,
- FALSE, cbd, g_free);
- return;
- }
+ decode_at_error(&error, g_at_result_final_response(result));
-done:
cb(&error, cbd->data);
-
- g_free(cbd);
}
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
@@ -845,12 +874,14 @@ static void at_pin_send(struct ofono_sim *sim, const char *passwd,
char buf[64];
int ret;
- cbd->user = sd;
+ cbd->user = sim;
+
+ sd->ready = FALSE;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
- at_pin_send_cb, cbd, NULL);
+ at_pin_send_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
@@ -871,12 +902,14 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
char buf[64];
int ret;
- cbd->user = sd;
+ cbd->user = sim;
+
+ sd->ready = FALSE;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
- at_pin_send_cb, cbd, NULL);
+ at_pin_send_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
@@ -1038,6 +1071,35 @@ static gboolean at_sim_register(gpointer user)
return FALSE;
}
+static void at_register_ready(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ switch (sd->vendor) {
+ case OFONO_VENDOR_IFX:
+ /*
+ * On the IFX modem, AT+CPIN? can return READY too
+ * early and so use +XSIM notification to detect
+ * the ready state of the SIM.
+ */
+ sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
+ at_xsim_notify,
+ FALSE, sim, NULL);
+ break;
+
+ case OFONO_VENDOR_MBM:
+ /*
+ * On the MBM modem, AT+CPIN? keeps returning SIM PIN
+ * for a moment after successful AT+CPIN="..", but then
+ * sends *EPEV when that changes.
+ */
+ sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
+ at_epev_notify,
+ FALSE, sim, NULL);
+ break;
+ }
+}
+
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
void *data)
{
@@ -1060,6 +1122,9 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
}
ofono_sim_set_data(sim, sd);
+
+ at_register_ready(sim);
+
g_idle_add(at_sim_register, sim);
return 0;
@@ -1071,6 +1136,9 @@ static void at_sim_remove(struct ofono_sim *sim)
ofono_sim_set_data(sim, NULL);
+ if (sd->ready_source > 0)
+ g_source_remove(sd->ready_source);
+
g_at_chat_unref(sd->chat);
g_free(sd);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [sim-ready-nofify-v5 PATCH 3/3] isimodem/sim: added PIN and SIM state handling
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Pekka.Pessi
@ 2011-02-08 12:32 ` Pekka.Pessi
2011-02-09 22:09 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Denis Kenzior
1 sibling, 0 replies; 6+ messages in thread
From: Pekka.Pessi @ 2011-02-08 12:32 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 24959 bytes --]
From: Pekka Pessi <Pekka.Pessi@nokia.com>
Using PN_SECURITY resource to obtain PIN statuses.
Using ofono_sim_ready_notify() to report the ready state.
---
drivers/isimodem/debug.c | 59 +++++
drivers/isimodem/debug.h | 6 +
drivers/isimodem/sim.c | 574 ++++++++++++++++++++++++++++++++++++++++-----
drivers/isimodem/sim.h | 50 ++++-
4 files changed, 624 insertions(+), 65 deletions(-)
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index 3d667b4..e641ba4 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -34,6 +34,8 @@
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sim.h>
#include "debug.h"
@@ -48,6 +50,7 @@ const char *pn_resource_name(int value)
_(PN_CALL);
_(PN_SMS);
_(PN_SIM);
+ _(PN_SECURITY);
_(PN_MTC);
_(PN_GSS);
_(PN_GPDS);
@@ -379,18 +382,72 @@ const char *sim_message_id_name(enum sim_message_id value)
_(SIM_IMSI_RESP_READ_IMSI);
_(SIM_SERV_PROV_NAME_REQ);
_(SIM_SERV_PROV_NAME_RESP);
+ _(SIM_DYNAMIC_FLAGS_REQ);
+ _(SIM_DYNAMIC_FLAGS_RESP);
_(SIM_READ_FIELD_REQ);
_(SIM_READ_FIELD_RESP);
_(SIM_SMS_REQ);
_(SIM_SMS_RESP);
+ _(SIM_STATUS_REQ);
+ _(SIM_STATUS_RESP);
_(SIM_PB_REQ_SIM_PB_READ);
_(SIM_PB_RESP_SIM_PB_READ);
+ _(SIM_SERVER_READY_IND);
_(SIM_IND);
_(SIM_COMMON_MESSAGE);
}
+
return "SIM_<UNKNOWN>";
}
+const char *sim_password_name(enum ofono_sim_password_type type)
+{
+ static const char *const passwd_name[] = {
+ [OFONO_SIM_PASSWORD_NONE] = "none",
+ [OFONO_SIM_PASSWORD_SIM_PIN] = "pin",
+ [OFONO_SIM_PASSWORD_SIM_PUK] = "puk",
+ [OFONO_SIM_PASSWORD_PHSIM_PIN] = "phone",
+ [OFONO_SIM_PASSWORD_PHFSIM_PIN] = "firstphone",
+ [OFONO_SIM_PASSWORD_PHFSIM_PUK] = "firstphonepuk",
+ [OFONO_SIM_PASSWORD_SIM_PIN2] = "pin2",
+ [OFONO_SIM_PASSWORD_SIM_PUK2] = "puk2",
+ [OFONO_SIM_PASSWORD_PHNET_PIN] = "network",
+ [OFONO_SIM_PASSWORD_PHNET_PUK] = "networkpuk",
+ [OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "netsub",
+ [OFONO_SIM_PASSWORD_PHNETSUB_PUK] = "netsubpuk",
+ [OFONO_SIM_PASSWORD_PHSP_PIN] = "service",
+ [OFONO_SIM_PASSWORD_PHSP_PUK] = "servicepuk",
+ [OFONO_SIM_PASSWORD_PHCORP_PIN] = "corp",
+ [OFONO_SIM_PASSWORD_PHCORP_PUK] = "corppuk",
+ [OFONO_SIM_PASSWORD_INVALID] = "invalid",
+ };
+
+ if (OFONO_SIM_PASSWORD_NONE <= (int)type &&
+ type <= OFONO_SIM_PASSWORD_PHCORP_PUK)
+ return passwd_name[type];
+ else
+ return "UNKNOWN";
+}
+
+const char *sec_message_id_name(enum sec_message_id value)
+{
+ switch (value) {
+ _(SEC_CODE_STATE_REQ);
+ _(SEC_CODE_STATE_OK_RESP);
+ _(SEC_CODE_STATE_FAIL_RESP);
+ _(SEC_CODE_CHANGE_REQ);
+ _(SEC_CODE_CHANGE_OK_RESP);
+ _(SEC_CODE_CHANGE_FAIL_RESP);
+ _(SEC_CODE_VERIFY_REQ);
+ _(SEC_CODE_VERIFY_OK_RESP);
+ _(SEC_CODE_VERIFY_FAIL_RESP);
+ _(SEC_STATE_REQ);
+ _(SEC_STATE_RESP);
+ }
+
+ return "SEC_<UNKNOWN>";
+}
+
const char *sim_subblock_name(enum sim_subblock value)
{
switch (value) {
@@ -1062,6 +1119,8 @@ static const char *res_to_name(uint8_t res, uint8_t id)
return ss_message_id_name(id);
case PN_CALL:
return call_message_id_name(id);
+ case PN_SECURITY:
+ return sec_message_id_name(id);
case PN_SMS:
return sms_message_id_name(id);
case PN_SIM:
diff --git a/drivers/isimodem/debug.h b/drivers/isimodem/debug.h
index e149c2c..08a5ab6 100644
--- a/drivers/isimodem/debug.h
+++ b/drivers/isimodem/debug.h
@@ -51,6 +51,12 @@ const char *sim_isi_cause_name(enum sim_isi_cause value);
const char *sim_message_id_name(enum sim_message_id value);
const char *sim_subblock_name(enum sim_subblock value);
+enum ofono_sim_password_type;
+
+const char *sim_password_name(enum ofono_sim_password_type value);
+
+const char *sec_message_id_name(enum sec_message_id value);
+
const char *info_isi_cause_name(enum info_isi_cause value);
const char *info_message_id_name(enum info_message_id value);
const char *info_subblock_name(enum info_subblock value);
diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
index bfecbc9..8c83642 100644
--- a/drivers/isimodem/sim.c
+++ b/drivers/isimodem/sim.c
@@ -48,7 +48,10 @@
struct sim_data {
GIsiClient *client;
- gboolean registered;
+ GIsiClient *sec_client;
+ enum ofono_sim_password_type passwd_state;
+ ofono_bool_t ready;
+ ofono_bool_t notify_ready;
};
struct sim_imsi {
@@ -75,6 +78,40 @@ struct file_info {
uint8_t file_status;
};
+static int sim_resp_status(const GIsiMessage *msg, uint8_t msgid,
+ uint8_t service)
+{
+ uint8_t type = 0;
+ uint8_t status;
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+ return -1;
+ }
+
+ if (g_isi_msg_id(msg) != msgid) {
+ DBG("Unexpected msg: %s",
+ sim_message_id_name(g_isi_msg_id(msg)));
+ return -1;
+ }
+
+ if (!g_isi_msg_data_get_byte(msg, 1, &status) ||
+ !g_isi_msg_data_get_byte(msg, 0, &type)) {
+ DBG("Runt msg: %s", sec_message_id_name(msgid));
+ return -1;
+ }
+
+ if (status != SIM_SERV_OK)
+ DBG("Request failed: %s", sim_isi_cause_name(status));
+
+ if (type != service) {
+ DBG("Unexpected service: 0x%02X", type);
+ return -1;
+ }
+
+ return status;
+}
+
/* Returns file info */
static gboolean fake_file_info(gpointer user)
{
@@ -115,30 +152,7 @@ static void isi_read_file_info(struct ofono_sim *sim, int fileid,
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
uint8_t service)
{
- uint8_t type;
- uint8_t cause;
-
- if (g_isi_msg_error(msg) < 0) {
- DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
- return FALSE;
- }
-
- if (g_isi_msg_id(msg) != msgid) {
- DBG("Unexpected msg: %s",
- sim_message_id_name(g_isi_msg_id(msg)));
- return FALSE;
- }
-
- if (!g_isi_msg_data_get_byte(msg, 1, &cause) || cause != SIM_SERV_OK) {
- DBG("Request failed: %s", sim_isi_cause_name(cause));
- return FALSE;
- }
-
- if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
- DBG("Unexpected service: 0x%02X", type);
- return FALSE;
- }
- return TRUE;
+ return sim_resp_status(msg, msgid, service) == SIM_SERV_OK;
}
static void spn_resp_cb(const GIsiMessage *msg, void *data)
@@ -191,9 +205,6 @@ static gboolean isi_read_spn(struct ofono_sim *sim, struct isi_cb_data *cbd)
0
};
- if (sd == NULL)
- return FALSE;
-
return g_isi_client_send(sd->client, msg, sizeof(msg),
spn_resp_cb, cbd, g_free);
}
@@ -227,9 +238,6 @@ static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
ICC,
};
- if (sd == NULL)
- return FALSE;
-
return g_isi_client_send(sd->client, req, sizeof(req),
read_iccid_resp_cb, cbd, g_free);
}
@@ -315,7 +323,7 @@ static void imsi_resp_cb(const GIsiMessage *msg, void *data)
struct isi_cb_data *cbd = data;
ofono_sim_imsi_cb_t cb = cbd->cb;
- struct sim_imsi *resp;
+ const struct sim_imsi *resp;
size_t len = sizeof(struct sim_imsi);
char imsi[SIM_MAX_IMSI_LENGTH + 1];
@@ -370,78 +378,496 @@ error:
g_free(cbd);
}
-static void isi_sim_register(struct ofono_sim *sim)
+static void isi_query_passwd_state(struct ofono_sim *sim,
+ ofono_sim_passwd_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
- if (sd && !sd->registered) {
- sd->registered = TRUE;
- ofono_sim_register(sim);
- ofono_sim_inserted_notify(sim, TRUE);
+ DBG("passwd_state %u", sd->passwd_state);
+
+ sd->notify_ready = TRUE;
+
+ if (sd->passwd_state != OFONO_SIM_PASSWORD_INVALID) {
+ CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
+
+ if (sd->ready)
+ ofono_sim_ready_notify(sim);
+ } else
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void sim_set_passwd_state(struct ofono_sim *sim,
+ enum ofono_sim_password_type pin_type)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ int inserted;
+ int previous;
+
+ if (pin_type == sd->passwd_state)
+ return;
+
+ DBG("new state \"%s\"", sim_password_name(pin_type));
+
+ inserted = pin_type != OFONO_SIM_PASSWORD_INVALID;
+ previous = sd->passwd_state != OFONO_SIM_PASSWORD_INVALID;
+
+ sd->passwd_state = pin_type;
+
+ if (pin_type != OFONO_SIM_PASSWORD_NONE) {
+ sd->ready = FALSE;
+ sd->notify_ready = FALSE;
}
+
+ if (inserted != previous)
+ ofono_sim_inserted_notify(sim, inserted);
}
-static void read_hplmn_resp_cb(const GIsiMessage *msg, void *data)
+static void check_sec_response(const GIsiMessage *msg, void *opaque,
+ uint8_t success, uint8_t failure)
{
- struct ofono_sim *sim = data;
+ struct isi_cb_data *cbd = opaque;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim *sim = cbd->user;
+ uint8_t id;
+ uint8_t cause;
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+ goto failure;
+ }
+
+ id = g_isi_msg_id(msg);
- if (!check_response_status(msg, SIM_NETWORK_INFO_RESP, READ_HPLMN))
+ if (id == success) {
+ DBG("%s", sec_message_id_name(id));
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_NONE);
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
return;
+ }
+
+ if (id == failure && g_isi_msg_data_get_byte(msg, 0, &cause)) {
+ DBG("%s(cause=%02x)", sec_message_id_name(id), cause);
- isi_sim_register(sim);
+ if (cause == SEC_CAUSE_CODE_BLOCKED)
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_SIM_PUK);
+ } else
+ DBG("Error msg: %s", sec_message_id_name(id));
+
+failure:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
+static void sec_code_verify_resp(const GIsiMessage *msg, void *opaque)
+{
+ check_sec_response(msg, opaque,
+ SEC_CODE_VERIFY_OK_RESP, SEC_CODE_VERIFY_FAIL_RESP);
+}
-static void isi_read_hplmn(struct ofono_sim *sim)
+static void isi_send_passwd(struct ofono_sim *sim, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ unsigned char msg[2 + SEC_CODE_MAX_LENGTH + 1] = {
+ SEC_CODE_VERIFY_REQ,
+ SEC_CODE_PIN,
+ };
+ int len = 2 + strlen(passwd) + 1;
- const uint8_t req[] = {
- SIM_NETWORK_INFO_REQ,
- READ_HPLMN, 0
+ DBG("");
+
+ if (!cbd)
+ goto error;
+
+ strcpy((char *) msg + 2, passwd);
+
+ if (g_isi_client_send(sd->sec_client, msg, len,
+ sec_code_verify_resp, cbd, g_free))
+ return;
+
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_reset_passwd(struct ofono_sim *sim,
+ const char *puk, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ enum ofono_sim_password_type passwd_type = OFONO_SIM_PASSWORD_SIM_PIN;
+ unsigned char msg[2 + 2 * (SEC_CODE_MAX_LENGTH + 1)] = {
+ SEC_CODE_VERIFY_REQ,
};
- size_t len = sizeof(req);
+ size_t len = sizeof(msg);
- if (sd == NULL)
+ DBG("");
+
+ if (!cbd)
+ goto error;
+
+ if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+ msg[1] = SEC_CODE_PUK;
+ else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+ msg[1] = SEC_CODE_PUK2;
+ else
+ goto error;
+
+ strcpy((char *) &msg[2], puk);
+ strcpy((char *) &msg[2 + SEC_CODE_MAX_LENGTH + 1], passwd);
+
+ if (g_isi_client_send(sd->sec_client, msg, len,
+ sec_code_verify_resp, cbd, g_free))
return;
- g_isi_client_send(sd->client, req, len, read_hplmn_resp_cb, sim, NULL);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+/* ISI callback: Enable/disable PIN */
+static void pin_enable_resp_cb(const GIsiMessage *msg, void *opaque)
+{
+ check_sec_response(msg, opaque,
+ SEC_CODE_STATE_OK_RESP, SEC_CODE_STATE_FAIL_RESP);
}
-static void sim_ind_cb(const GIsiMessage *msg, void *data)
+static void isi_lock(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ int enable, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
{
- struct ofono_sim *sim = data;
struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+ unsigned char req[3 + SEC_CODE_MAX_LENGTH + 1] = {
+ SEC_CODE_STATE_REQ,
+ };
+
+ if (!cbd)
+ goto error;
+
+ DBG("enable %d pintype %d pass %s", enable, passwd_type, passwd);
+
+ if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+ req[1] = SEC_CODE_PIN;
+ else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+ req[1] = SEC_CODE_PIN2;
+ else
+ goto error;
+
+ if (enable)
+ req[2] = SEC_CODE_ENABLE;
+ else
+ req[2] = SEC_CODE_DISABLE;
+
+ strcpy((char *) &req[3], passwd);
+
+ if (g_isi_client_send(sd->sec_client, req, sizeof(req),
+ pin_enable_resp_cb, cbd, g_free))
+ return;
+
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+/* ISI callback: PIN state (enabled/disabled) query */
+static void sec_code_change_resp(const GIsiMessage *msg, void *opaque)
+{
+ check_sec_response(msg, opaque,
+ SEC_CODE_CHANGE_OK_RESP, SEC_CODE_CHANGE_FAIL_RESP);
+}
+
+
+static void isi_change_passwd(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ const char *old, const char *new,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ unsigned char msg[2 + 2 * (SEC_CODE_MAX_LENGTH + 1)] = {
+ SEC_CODE_CHANGE_REQ,
+ };
+
+ DBG("passwd_type %d", passwd_type);
+
+ if (!cbd)
+ goto error;
+
+ if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+ msg[1] = SEC_CODE_PIN;
+ else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+ msg[1] = SEC_CODE_PIN2;
+ else
+ goto error;
+
+ strcpy((char *) &msg[2], old);
+ strcpy((char *) &msg[2 + SEC_CODE_MAX_LENGTH + 1], new);
+
+ if (g_isi_client_send(sd->sec_client, msg, sizeof(msg),
+ sec_code_change_resp, cbd, g_free))
+ return;
+
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+/* ISI callback: PIN state (enabled/disabled) query */
+static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
+{
+ check_sec_response(msg, opaque,
+ SEC_CODE_STATE_OK_RESP, SEC_CODE_STATE_FAIL_RESP);
+}
+
+static void isi_query_locked(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ ofono_sim_locked_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+ unsigned char msg[] = {
+ SEC_CODE_STATE_REQ,
+ 0,
+ SEC_CODE_STATE_QUERY
+ };
+
+ DBG("");
+
+ if (!cbd)
+ goto error;
+
+ if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+ msg[1] = SEC_CODE_PIN;
+ else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+ msg[1] = SEC_CODE_PIN2;
+ else
+ goto error;
+
+ if (g_isi_client_send(sd->sec_client, msg, sizeof(msg),
+ sec_code_state_resp_cb, cbd, g_free))
+ return;
+
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void sim_ind_cb(const GIsiMessage *msg, void *opaque)
+{
+ struct ofono_sim *sim = opaque;
+ uint8_t service;
uint8_t status;
- if (sd == NULL || g_isi_msg_id(msg) != SIM_IND || sd->registered)
+ DBG("");
+
+ if (g_isi_msg_id(msg) != SIM_IND ||
+ !g_isi_msg_data_get_byte(msg, 0, &service) ||
+ !g_isi_msg_data_get_byte(msg, 1, &status))
+ return;
+
+ if (status == SIM_SERV_PIN_VERIFY_REQUIRED && service == SIM_ST_PIN)
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_SIM_PIN);
+ else if (status == SIM_SERV_SIM_BLOCKED)
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_SIM_PUK);
+ else if (status == SIM_SERV_INIT_OK && service == SIM_ST_INFO)
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_NONE);
+ else if (status == SIM_SERV_SIM_DISCONNECTED)
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_INVALID);
+}
+
+static void sim_server_ready_ind_cb(const GIsiMessage *msg, void *opaque)
+{
+ struct ofono_sim *sim = opaque;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ DBG("");
+
+ if (sd == NULL || g_isi_msg_id(msg) != SIM_SERVER_READY_IND)
+ return;
+
+ sd->ready = TRUE;
+
+ if (sd->notify_ready)
+ ofono_sim_ready_notify(sim);
+}
+
+static void read_dyn_flags_cb(const GIsiMessage *msg, void *opaque)
+{
+ struct ofono_sim *sim = opaque;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ int status;
+
+ status = sim_resp_status(msg, SIM_DYNAMIC_FLAGS_RESP, READ_DYN_FLAGS);
+
+ if (status < 0 || status == SIM_SERV_NOTREADY)
+ return;
+
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_NONE);
+
+ sd->ready = TRUE;
+
+ if (sd->notify_ready)
+ ofono_sim_ready_notify(sim);
+}
+
+static void read_dyn_flags_req(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ unsigned char req[] = {
+ SIM_DYNAMIC_FLAGS_REQ,
+ READ_DYN_FLAGS,
+ 0
+ };
+
+ g_isi_client_send(sd->client, req, sizeof(req),
+ read_dyn_flags_cb, sim, NULL);
+}
+
+static void sec_state_resp_cb(const GIsiMessage *msg, void *opaque)
+{
+ struct ofono_sim *sim = opaque;
+ uint8_t msgid;
+ uint8_t cause;
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
return;
+ }
- if (!g_isi_msg_data_get_byte(msg, 0, &status))
+ msgid = g_isi_msg_id(msg);
+
+ if (msgid != SEC_STATE_RESP) {
+ DBG("Unexpected msg: %s", sec_message_id_name(msgid));
return;
+ }
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &cause)) {
+ DBG("Runt msg: %s", sec_message_id_name(msgid));
+ return;
+ }
+
+ DBG("%s(cause=0x%0x)", sec_message_id_name(msgid), cause);
+
+ switch (cause) {
+ case SEC_STARTUP_OK:
+ DBG("SEC_STARTUP_OK");
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_NONE);
+ /* Check if SIM server is already ready */
+ read_dyn_flags_req(sim);
+ break;
+
+ case SEC_CAUSE_PIN_REQUIRED:
+ DBG("SEC_CAUSE_PIN_REQUIRED");
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_SIM_PIN);
+ break;
+
+ case SEC_CAUSE_PUK_REQUIRED:
+ DBG("SEC_CAUSE_PUK_REQUIRED");
+ sim_set_passwd_state(sim, OFONO_SIM_PASSWORD_SIM_PIN);
+ break;
+
+ case SEC_CAUSE_NO_SIM:
+ DBG("SEC_CAUSE_NO_SIM");
+ break;
- switch (status) {
- case SIM_ST_PIN:
- isi_sim_register(sim);
+ case SEC_CAUSE_INVALID_SIM:
+ DBG("SEC_CAUSE_INVALID_SIM");
break;
- case SIM_ST_INFO:
- isi_read_hplmn(sim);
+ case SEC_CAUSE_SIM_REJECTED:
+ DBG("SEC_CAUSE_SIM_REJECTED");
+ break;
+
+ default:
break;
}
}
+static void isi_sec_state_req(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ unsigned char req[] = {
+ SEC_STATE_REQ,
+ 0,
+ 0
+ };
+
+ g_isi_client_send(sd->sec_client, req, sizeof(req),
+ sec_state_resp_cb, sim, NULL);
+}
+
+static void sim_status_resp_cb(const GIsiMessage *msg, void *opaque)
+{
+ struct ofono_sim *sim = opaque;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ int status = sim_resp_status(msg, SIM_STATUS_RESP, SIM_ST_CARD_STATUS);
+
+ if (status < 0 || status == SIM_SERV_SIM_DISCONNECTED)
+ return;
+
+ /* We probably have a SIM. */
+ if (sd->sec_client)
+ isi_sec_state_req(sim);
+ else
+ read_dyn_flags_req(sim);
+}
+
+static void isi_sim_status_req(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ const unsigned char req[] = {
+ SIM_STATUS_REQ,
+ SIM_ST_CARD_STATUS
+ };
+
+ g_isi_client_send(sd->client, req, sizeof(req),
+ sim_status_resp_cb, sim, NULL);
+}
+
+static void sec_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("PN_SECURITY: %s", strerror(-g_isi_msg_error(msg)));
+ DBG("PIN code handling not available");
+ g_isi_client_destroy(sd->sec_client);
+ sd->sec_client = NULL;
+ }
+
+ g_isi_client_ind_subscribe(sd->client, SIM_IND, sim_ind_cb, sim);
+ g_isi_client_ind_subscribe(sd->client, SIM_SERVER_READY_IND,
+ sim_server_ready_ind_cb, sim);
+ /* Check if we have a SIM */
+ isi_sim_status_req(sim);
+
+ ofono_sim_register(sim);
+}
+
static void sim_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_sim *sim = data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
- if (g_isi_msg_error(msg) < 0)
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("PN_SIM: %s", strerror(-g_isi_msg_error(msg)));
return;
+ }
ISI_VERSION_DBG(msg);
- /* Check if SIM is ready by reading HPLMN */
- isi_read_hplmn(sim);
+ g_isi_client_verify(sd->sec_client, sec_reachable_cb, sim, NULL);
}
static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
@@ -454,11 +880,18 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
if (sd == NULL)
return -ENOMEM;
+ sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
+
sd->client = g_isi_client_create(modem, PN_SIM);
- if (sd->client == NULL) {
- g_free(sd);
- return -ENOMEM;
- }
+ if (sd->client == NULL)
+ goto error;
+
+ sd->sec_client = g_isi_client_create(modem, PN_SECURITY);
+ if (sd->sec_client == NULL)
+ goto error;
+
+ g_isi_client_set_timeout(sd->client, SIM_TIMEOUT);
+ g_isi_client_set_timeout(sd->sec_client, SIM_TIMEOUT);
ofono_sim_set_data(sim, sd);
@@ -466,6 +899,12 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
g_isi_client_verify(sd->client, sim_reachable_cb, sim, NULL);
return 0;
+
+error:
+ g_isi_client_destroy(sd->client);
+ g_isi_client_destroy(sd->sec_client);
+
+ return -ENOMEM;
}
static void isi_sim_remove(struct ofono_sim *sim)
@@ -478,6 +917,7 @@ static void isi_sim_remove(struct ofono_sim *sim)
return;
g_isi_client_destroy(data->client);
+ g_isi_client_destroy(data->sec_client);
g_free(data);
}
@@ -493,6 +933,12 @@ static struct ofono_sim_driver driver = {
.write_file_linear = isi_write_file_linear,
.write_file_cyclic = isi_write_file_cyclic,
.read_imsi = isi_read_imsi,
+ .query_passwd_state = isi_query_passwd_state,
+ .send_passwd = isi_send_passwd,
+ .reset_passwd = isi_reset_passwd,
+ .lock = isi_lock,
+ .change_passwd = isi_change_passwd,
+ .query_locked = isi_query_locked,
};
void isi_sim_init(void)
diff --git a/drivers/isimodem/sim.h b/drivers/isimodem/sim.h
index 9b2b076..1585906 100644
--- a/drivers/isimodem/sim.h
+++ b/drivers/isimodem/sim.h
@@ -28,6 +28,7 @@ extern "C" {
#define PN_SIM 0x09
#define SIM_TIMEOUT 5
+#define PN_SECURITY 0x08
#define SIM_MAX_IMSI_LENGTH 15
enum sim_isi_cause {
@@ -131,31 +132,78 @@ enum sim_message_id {
SIM_IMSI_RESP_READ_IMSI = 0x1E,
SIM_SERV_PROV_NAME_REQ = 0x21,
SIM_SERV_PROV_NAME_RESP = 0x22,
+ SIM_DYNAMIC_FLAGS_REQ = 0x29,
+ SIM_DYNAMIC_FLAGS_RESP = 0x2A,
SIM_READ_FIELD_REQ = 0xBA,
SIM_READ_FIELD_RESP = 0xBB,
SIM_SMS_REQ = 0xBC,
SIM_SMS_RESP = 0xBD,
+ SIM_STATUS_REQ = 0xC0,
+ SIM_STATUS_RESP = 0xC1,
SIM_PB_REQ_SIM_PB_READ = 0xDC,
SIM_PB_RESP_SIM_PB_READ = 0xDD,
+ SIM_SERVER_READY_IND = 0xED,
SIM_IND = 0xEF,
SIM_COMMON_MESSAGE = 0xF0,
};
enum sim_service_type {
+ SIM_ST_CARD_STATUS = 0x00,
SIM_ST_PIN = 0x01,
SIM_ST_ALL_SERVICES = 0x05,
SIM_ST_INFO = 0x0D,
+ SIM_PB_READ = 0x0F,
SIM_ST_CAT_SUPPORT_ENABLE = 0x15,
SIM_ST_CAT_SUPPORT_DISABLE = 0x16,
SIM_ST_READ_SERV_PROV_NAME = 0x2C,
- SIM_PB_READ = 0x0F,
READ_IMSI = 0x2D,
READ_HPLMN = 0x2F,
+ READ_DYN_FLAGS = 0x35,
READ_PARAMETER = 0x52,
UPDATE_PARAMETER = 0x53,
ICC = 0x66,
};
+#define SEC_CODE_MAX_LENGTH 0x0A
+
+enum sec_message_id {
+ SEC_CODE_STATE_REQ = 0x01,
+ SEC_CODE_STATE_OK_RESP = 0x02,
+ SEC_CODE_STATE_FAIL_RESP = 0x03,
+ SEC_CODE_CHANGE_REQ = 0x04,
+ SEC_CODE_CHANGE_OK_RESP = 0x05,
+ SEC_CODE_CHANGE_FAIL_RESP = 0x06,
+ SEC_CODE_VERIFY_REQ = 0x07,
+ SEC_CODE_VERIFY_OK_RESP = 0x08,
+ SEC_CODE_VERIFY_FAIL_RESP = 0x09,
+ SEC_STATE_REQ = 0x11,
+ SEC_STATE_RESP = 0x12,
+};
+
+enum sec_code_id_info {
+ SEC_CODE_PIN = 0x02,
+ SEC_CODE_PUK = 0x03,
+ SEC_CODE_PIN2 = 0x04,
+ SEC_CODE_PUK2 = 0x05,
+};
+
+enum sec_code_state_info {
+ SEC_CODE_DISABLE = 0x00,
+ SEC_CODE_ENABLE = 0x01,
+ SEC_CODE_STATE_QUERY = 0x04,
+};
+
+enum sec_state_cause_info {
+ SEC_CAUSE_PIN_REQUIRED = 0x02,
+ SEC_CAUSE_PUK_REQUIRED = 0x03,
+ SEC_STARTUP_OK = 0x05,
+ SEC_STARTUP_ONGOING = 0x07,
+ SEC_CAUSE_CODE_BLOCKED = 0x08,
+ SEC_CAUSE_NO_SIM = 0x16,
+ SEC_CAUSE_SIM_REJECTED = 0x1A,
+ SEC_CAUSE_INVALID_SIM = 0x1E,
+};
+
#ifdef __cplusplus
};
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 3/3] isimodem/sim: added PIN and SIM state handling Pekka.Pessi
@ 2011-02-09 22:09 ` Denis Kenzior
2011-02-15 15:30 ` Pekka Pessi
1 sibling, 1 reply; 6+ messages in thread
From: Denis Kenzior @ 2011-02-09 22:09 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 10323 bytes --]
Hi Pekka,
On 02/08/2011 06:32 AM, Pekka.Pessi(a)nokia.com wrote:
> From: Pekka Pessi <Pekka.Pessi@nokia.com>
>
> Schedule a call to ofono_sim_ready_notify after pin code query returns
> SIM READY.
>
> Vendor quirks:
> - IFX: register unsolicated +XSIM result code
> - MBM: register unsolicated *EPEV result code
> ---
> drivers/atmodem/sim.c | 166 ++++++++++++++++++++++++++++++++++--------------
> 1 files changed, 117 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
> index d9c0d8d..666edbe 100644
> --- a/drivers/atmodem/sim.c
> +++ b/drivers/atmodem/sim.c
> @@ -46,10 +46,14 @@
>
> #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
>
> +#define READY_TIMEOUT 5000
> +
> struct sim_data {
> GAtChat *chat;
> unsigned int vendor;
> guint ready_id;
> + guint ready_source;
> + ofono_bool_t ready;
> };
>
> static const char *crsm_prefix[] = { "+CRSM:", NULL };
> @@ -679,10 +683,55 @@ static void at_pin_retries_query(struct ofono_sim *sim,
> CALLBACK_WITH_FAILURE(cb, NULL, data);
> }
>
> +static void ready_unregister_and_notify(struct ofono_sim *sim)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + DBG("");
> +
> + if (sd->ready_source > 0) {
> + g_source_remove(sd->ready_source);
> + sd->ready_source = 0;
> + }
> +
> + ofono_sim_ready_notify(sim);
> +}
> +
> +static gboolean ready_timeout(gpointer user_data)
> +{
> + struct ofono_sim *sim = user_data;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + DBG("");
> +
> + sd->ready_source = 0;
> +
> + ofono_sim_ready_notify(sim);
> +
> + return FALSE;
> +}
> +
> +static void at_wait_for_ready(struct ofono_sim *sim)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + guint timeout;
> +
> + if (sd->ready_source > 0)
> + return;
> +
> + if (!sd->ready && sd->ready_id > 0)
> + timeout = READY_TIMEOUT;
> + else
> + timeout = 0;
> +
> + sd->ready_source = g_timeout_add(timeout, ready_timeout, sim);
> +}
> +
> static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
> {
> struct cb_data *cbd = user_data;
> - struct sim_data *sd = ofono_sim_get_data(cbd->user);
> + struct ofono_sim *sim = cbd->user;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> GAtResultIter iter;
> ofono_sim_passwd_cb_t cb = cbd->cb;
> struct ofono_error error;
> @@ -729,6 +778,11 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
> return;
> }
>
> + if (pin_type == OFONO_SIM_PASSWORD_NONE)
> + at_wait_for_ready(sim);
> + else
> + sd->ready = FALSE;
> +
So all this logic seems to work by luck. oFono roughly does this:
pin_query:
send AT+CPIN?
if READY then set waiting_for_pin to none, and wait in
ofono_sim_ready_notify
if PIN then set waiting_for_pin to the pin, and wait in
ofono_sim_ready_notify
ofono_sim_ready_notify:
if waiting_for_pin is none proceed with initialization
otherwise go back to pin_query
Here's a log of this running on IFX:
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CPIN: SIM PIN\r\n
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: SIM PIN
....
ofonod[521]: Aux: > AT+CPIN="0000"\r
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CME ERROR: 14\r\n
ofonod[521]: Querying PIN authentication state failed
....
ofonod[521]: Aux: < \r\n+XSIM: 7\r\n
ofonod[521]: drivers/atmodem/sim.c:at_xsim_notify()
ofonod[521]: drivers/atmodem/sim.c:ready_unregister_and_notify()
ofonod[521]: src/sim.c:ofono_sim_ready_notify()
ofonod[521]: plugins/ifx.c:xsim_notify() state 7
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CPIN: READY\r\n
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: READY
ofonod[521]: drivers/atmodem/sim.c:at_pin_retries_query()
ofonod[521]: drivers/atmodem/sim.c:ready_timeout()
ofonod[521]: src/sim.c:ofono_sim_ready_notify()
As you can see, we are in fact calling ofono_sim_ready_notify twice in
short succession. The only reason we're not stuck for 5 seconds the
second time around is that the xsim notification function sets ready to
TRUE. This is all pretty convoluted. I don't really like this@all.
Another case to consider is a cold boot quirked modem, PIN disabled. We
are highly likely to receive XSIM way before we even query the PIN. So
ready is false, ready_id is > 0 and we end up waiting for 5 seconds here
for no good reason.
> DBG("crsm_pin_cb: %s", pin_required);
>
> cb(&error, pin_type, cbd->data);
> @@ -753,13 +807,13 @@ static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
>
> static void at_xsim_notify(GAtResult *result, gpointer user_data)
> {
> - struct cb_data *cbd = user_data;
> - struct sim_data *sd = cbd->user;
> - ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> - struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
> + struct ofono_sim *sim = user_data;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> GAtResultIter iter;
> int state;
>
> + DBG("");
> +
> g_at_result_iter_init(&iter, result);
>
> if (!g_at_result_iter_next(&iter, "+XSIM:"))
> @@ -776,65 +830,40 @@ static void at_xsim_notify(GAtResult *result, gpointer user_data)
> return;
> }
>
> - cb(&error, cbd->data);
> + sd->ready = TRUE;
>
> - g_at_chat_unregister(sd->chat, sd->ready_id);
> - sd->ready_id = 0;
> + if (sd->ready_source > 0)
> + ready_unregister_and_notify(sim);
> }
>
> static void at_epev_notify(GAtResult *result, gpointer user_data)
> {
> - struct cb_data *cbd = user_data;
> - struct sim_data *sd = cbd->user;
> - ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> - struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
> + struct ofono_sim *sim = user_data;
> + struct sim_data *sd = ofono_sim_get_data(sim);
>
> - cb(&error, cbd->data);
> + DBG("");
>
> - g_at_chat_unregister(sd->chat, sd->ready_id);
> - sd->ready_id = 0;
> + sd->ready = TRUE;
> +
> + if (sd->ready_source > 0)
> + ready_unregister_and_notify(sim);
> }
>
> static void at_pin_send_cb(gboolean ok, GAtResult *result,
> gpointer user_data)
> {
> struct cb_data *cbd = user_data;
> - struct sim_data *sd = cbd->user;
> + struct ofono_sim *sim = cbd->user;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> struct ofono_error error;
>
> - decode_at_error(&error, g_at_result_final_response(result));
> + if (ok && sd->ready_id)
> + at_wait_for_ready(sim);
Did you intend if (ok && sd_ready_id == 0) here?
Otherwise I don't see how non-quirked modems ever signal sim_ready or
why you would want to start a timer if you know a notification is coming
anyway.
>
> - if (!ok)
> - goto done;
> -
> - switch (sd->vendor) {
> - case OFONO_VENDOR_IFX:
> - /*
> - * On the IFX modem, AT+CPIN? can return READY too
> - * early and so use +XSIM notification to detect
> - * the ready state of the SIM.
> - */
> - sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
> - at_xsim_notify,
> - FALSE, cbd, g_free);
> - return;
> - case OFONO_VENDOR_MBM:
> - /*
> - * On the MBM modem, AT+CPIN? keeps returning SIM PIN
> - * for a moment after successful AT+CPIN="..", but then
> - * sends *EPEV when that changes.
> - */
> - sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
> - at_epev_notify,
> - FALSE, cbd, g_free);
> - return;
> - }
> + decode_at_error(&error, g_at_result_final_response(result));
>
> -done:
> cb(&error, cbd->data);
> -
> - g_free(cbd);
> }
>
> static void at_pin_send(struct ofono_sim *sim, const char *passwd,
> @@ -845,12 +874,14 @@ static void at_pin_send(struct ofono_sim *sim, const char *passwd,
> char buf[64];
> int ret;
>
> - cbd->user = sd;
> + cbd->user = sim;
> +
> + sd->ready = FALSE;
>
> snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
>
> ret = g_at_chat_send(sd->chat, buf, none_prefix,
> - at_pin_send_cb, cbd, NULL);
> + at_pin_send_cb, cbd, g_free);
>
> memset(buf, 0, sizeof(buf));
>
> @@ -871,12 +902,14 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
> char buf[64];
> int ret;
>
> - cbd->user = sd;
> + cbd->user = sim;
> +
> + sd->ready = FALSE;
>
> snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
>
> ret = g_at_chat_send(sd->chat, buf, none_prefix,
> - at_pin_send_cb, cbd, NULL);
> + at_pin_send_cb, cbd, g_free);
>
> memset(buf, 0, sizeof(buf));
>
> @@ -1038,6 +1071,35 @@ static gboolean at_sim_register(gpointer user)
> return FALSE;
> }
>
> +static void at_register_ready(struct ofono_sim *sim)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + switch (sd->vendor) {
> + case OFONO_VENDOR_IFX:
> + /*
> + * On the IFX modem, AT+CPIN? can return READY too
> + * early and so use +XSIM notification to detect
> + * the ready state of the SIM.
> + */
> + sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
> + at_xsim_notify,
> + FALSE, sim, NULL);
> + break;
> +
> + case OFONO_VENDOR_MBM:
> + /*
> + * On the MBM modem, AT+CPIN? keeps returning SIM PIN
> + * for a moment after successful AT+CPIN="..", but then
> + * sends *EPEV when that changes.
> + */
> + sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
> + at_epev_notify,
> + FALSE, sim, NULL);
> + break;
> + }
> +}
> +
> static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
> void *data)
> {
> @@ -1060,6 +1122,9 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
> }
>
> ofono_sim_set_data(sim, sd);
> +
> + at_register_ready(sim);
> +
> g_idle_add(at_sim_register, sim);
>
> return 0;
> @@ -1071,6 +1136,9 @@ static void at_sim_remove(struct ofono_sim *sim)
>
> ofono_sim_set_data(sim, NULL);
>
> + if (sd->ready_source > 0)
> + g_source_remove(sd->ready_source);
> +
> g_at_chat_unref(sd->chat);
> g_free(sd);
> }
Regards,
-Denis
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify
2011-02-09 22:09 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Denis Kenzior
@ 2011-02-15 15:30 ` Pekka Pessi
0 siblings, 0 replies; 6+ messages in thread
From: Pekka Pessi @ 2011-02-15 15:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3399 bytes --]
Hi Denis,
2011/2/10 Denis Kenzior <denkenz@gmail.com>:
> So all this logic seems to work by luck.
AFAIK that is the way you wanted it. Continue initialization after
1) pin query returns None, and
2) notify is called after that.
If notify is called when pin is not None, recheck pin.
> oFono roughly does this:
> pin_query:
> send AT+CPIN?
> if READY then set waiting_for_pin to none, and wait in
> ofono_sim_ready_notify
> if PIN then set waiting_for_pin to the pin, and wait in
> ofono_sim_ready_notify
>
> ofono_sim_ready_notify:
> if waiting_for_pin is none proceed with initialization
> otherwise go back to pin_query
Sounds about correct.
> Here's a log of this running on IFX:
> ofonod[521]: Aux: > AT+CPIN?\r
> ofonod[521]: Aux: < \r\n+CPIN: SIM PIN\r\n
> ofonod[521]: Aux: < \r\nOK\r\n
> ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: SIM PIN
> ....
> ofonod[521]: Aux: > AT+CPIN="0000"\r
> ofonod[521]: Aux: < \r\nOK\r\n
> ofonod[521]: Aux: > AT+CPIN?\r
> ofonod[521]: Aux: < \r\n+CME ERROR: 14\r\n
> ofonod[521]: Querying PIN authentication state failed
> ....
> ofonod[521]: Aux: < \r\n+XSIM: 7\r\n
> ofonod[521]: drivers/atmodem/sim.c:at_xsim_notify()
> ofonod[521]: drivers/atmodem/sim.c:ready_unregister_and_notify()
> ofonod[521]: src/sim.c:ofono_sim_ready_notify()
> ofonod[521]: plugins/ifx.c:xsim_notify() state 7
> ofonod[521]: Aux: > AT+CPIN?\r
> ofonod[521]: Aux: < \r\n+CPIN: READY\r\n
> ofonod[521]: Aux: < \r\nOK\r\n
> ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: READY
> ofonod[521]: drivers/atmodem/sim.c:at_pin_retries_query()
> ofonod[521]: drivers/atmodem/sim.c:ready_timeout()
> ofonod[521]: src/sim.c:ofono_sim_ready_notify()
>
> As you can see, we are in fact calling ofono_sim_ready_notify twice in
> short succession. The only reason we're not stuck for 5 seconds the
> second time around is that the xsim notification function sets ready to
> TRUE.
That is the way it was designed.
Second time around driver knows SIM is ready, so it schedules a call
to ofono_sim_ready_notify() in at_wait_for_ready().
We could avoid extra AT+CPIN? if needed, e.g., at_pin_query() could
return error immediately if ready_source is set.
>This is all pretty convoluted. I don't really like this at all.
It is. How would you like to clarify the code? Better naming for
functions, comments?
> Another case to consider is a cold boot quirked modem, PIN disabled. We
> are highly likely to receive XSIM way before we even query the PIN. So
> ready is false, ready_id is > 0 and we end up waiting for 5 seconds here
> for no good reason.
The +XSIM etc. is subscribed when SIM atom is probed, so oFono ends up
waiting only if SIM probe is done after ready indication. For MBM,
there is no good way to find out the SIM readyness (apart from reading
something from the SIM). For IFX, I think we could check the state
with an AT+XSIMSTATE? request.
> Did you intend if (ok && sd_ready_id == 0) here?
>
> Otherwise I don't see how non-quirked modems ever signal sim_ready or
> why you would want to start a timer if you know a notification is coming
> anyway.
The at_wait_for_ready() will schedule immediately a callback (timer
with timeout of 0) if modem has not registered a ready indication
(ready_id is 0).
--
Pekka.Pessi mail at nokia.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-02-15 15:30 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-08 12:32 [sim-ready-nofify-v5 PATCH 0/3] ofono_sim_ready_notify Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 1/3] sim: add ofono_sim_ready_notify Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Pekka.Pessi
2011-02-08 12:32 ` [sim-ready-nofify-v5 PATCH 3/3] isimodem/sim: added PIN and SIM state handling Pekka.Pessi
2011-02-09 22:09 ` [sim-ready-nofify-v5 PATCH 2/3] atmodem/sim: use ofono_sim_ready_notify Denis Kenzior
2011-02-15 15:30 ` Pekka Pessi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.