Hi,
2011/2/15 Andreas Westin <andreas.westin(a)stericsson.com>:
(snip)
diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
index bfecbc9..0ef02f3 100644
--- a/drivers/isimodem/sim.c
+++ b/drivers/isimodem/sim.c
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,24 +34,216 @@
#include <gisi/message.h>
#include <gisi/client.h>
+#include <gisi/iter.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/sim.h>
-#include "simutil.h"
+#include <ofono/dbus.h>
+#include "simutil.h"
#include "isimodem.h"
#include "isiutil.h"
#include "sim.h"
+#include "uicc.h"
#include "debug.h"
-#define SIM_MAX_SPN_LENGTH 16
+#define PIN_PROMPT
+#define STATUS_WORD_HANDLING
+
+#define SIM_MAX_SPN_LENGTH 16
+#define CLIENT_ID 1
+
+
+/* File info parameters */
+#define FCP_TEMPLATE 0x62
+#define FCP_FILE_SIZE 0x80
+#define FCP_FILE_DESC 0x82
+#define FCP_FILE_ID 0x83
+#define FCP_FILE_LIFECYCLE 0x8A
+#define FCP_FILE_SECURITY_ARR 0x8B
+#define FCP_FILE_SECURITY_COMPACT 0x8C
+#define FCP_FILE_SECURITY_EXPANDED 0xAB
+#define FCP_PIN_STATUS 0xC6
This should be an enum.
+#define SIM_EFARR_FILEID 0x6F06
Why is this not in simutil.h?
+#define ADF_USIM 0x7FFF
+#define MAX_SIM_APPS 10
+#define NOT_AVAILABLE -1
+#define NOT_ACTIVATED -1
struct sim_data {
GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
+ gboolean iccid;
gboolean registered;
+ gboolean uicc_app_started;
+ gboolean pin_state_received;
+ gboolean passwd_required;
+ int app_id;
+ int trying_app_id;
+ int app_type;
+ int trying_app_type;
+ uint8_t client_id;
+ uint8_t current_pin_id;
+ uint8_t pin1_id;
+ uint8_t pin2_id;
+};
+
+struct ofono_sim_local {
+ char *iccid;
+ char *imsi;
+ enum ofono_sim_phase phase;
+ unsigned char mnc_length;
+ GSList *own_numbers;
+ GSList *new_numbers;
+ GSList *service_numbers;
+ gboolean sdn_ready;
+ enum ofono_sim_state state;
+ enum ofono_sim_password_type pin_type;
+ gboolean locked_pins[OFONO_SIM_PASSWORD_INVALID];
+ char **language_prefs;
+ GQueue *simop_q;
+ gint simop_source;
+ unsigned char efmsisdn_length;
+ unsigned char efmsisdn_records;
+ unsigned char *efli;
+ unsigned char efli_length;
+ enum ofono_sim_cphs_phase cphs_phase;
+ unsigned char cphs_service_table[2];
+ struct ofono_watchlist *state_watches;
+ const struct ofono_sim_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
+ DBusMessage *pending;
+};
+
+struct sim_passwd_to_pin_id {
+ uint8_t passwd_type;
+ uint8_t pin_id;
+};
+
+static struct sim_passwd_to_pin_id const pin_ids[] = {
+ {OFONO_SIM_PASSWORD_NONE, 0},
+ {OFONO_SIM_PASSWORD_SIM_PIN, 1},
+ {OFONO_SIM_PASSWORD_PHSIM_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHFSIM_PIN, 0},
+ {OFONO_SIM_PASSWORD_SIM_PIN2, -1},
+ {OFONO_SIM_PASSWORD_PHNET_PIN, 0x11},
+ {OFONO_SIM_PASSWORD_PHNETSUB_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHSP_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHCORP_PIN, 0},
+ {OFONO_SIM_PASSWORD_SIM_PUK, -1},
+ {OFONO_SIM_PASSWORD_PHFSIM_PUK, 0},
+ {OFONO_SIM_PASSWORD_SIM_PUK2, -1},
+ {OFONO_SIM_PASSWORD_PHNET_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHNETSUB_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHSP_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHCORP_PUK, 0},
+ {OFONO_SIM_PASSWORD_INVALID, 0}
+};
I don't like you mixing hex and decimal values, and above all, some of
these are also assigning signed values to an unsigned variable.
+
+const uint8_t upin_id = 0x11;
+
+/* Current SIM */
+static struct ofono_sim *uicc_sim;
+/* UICC client */
+static GIsiClient *pn_uicc_client;
+static int uicc_users;
I doubt this is going to work.
So what happens when someone plugs in two isimodems into the system?
Is there a specific reason that the UICC client needs to be shared
among the rest of the drivers? Why can't each of them just create
their own instance, and let the gisi modem handle the client reuse
optimizations.
+
+struct sim_applications {
+ int app_list[MAX_SIM_APPS];
+ int app_type[MAX_SIM_APPS];
+};
+
+struct sim_applications *sim_application_list_p;
Is this a global list, or a per-modem list?
+struct file_info {
+ int fileid;
+ int length;
+ int structure;
+ int record_length;
+ uint8_t access[3];
+ uint8_t file_status;
+};
+
+static struct file_info const static_file_info[] = {
+ {
+ SIM_EFSPN_FILEID, 17, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 0, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EF_ICCID_FILEID, 10, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 10, { 0x0f, 0xff, 0xee }
+ },
+ {
+ SIM_EFPL_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0f, 0xff, 0xff }
+ }, /* not found */
+ {
+ SIM_EFLI_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0f, 0xff, 0xff }
+ }, /* not found */
+ {
+ SIM_EFMSISDN_FILEID, 28, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 28, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFAD_FILEID, 20, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 20, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFPHASE_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFPNN_FILEID, 4 * 18, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 18, { 0x0e, 0xff, 0xee }
+ }, /* 4 records, name 16 bytes */
+ {
+ SIM_EFOPL_FILEID, 4 * 24, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 24, { 0x0e, 0xff, 0xee }
+ }, /* 4 records, name 16 bytes */
+ {
+ SIM_EFMBI_FILEID, 5, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 5, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFMWIS_FILEID, 6, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 6, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFSPDI_FILEID, 64, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 64, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFECC_FILEID, 5 * 3, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 3, { 0x0e, 0xff, 0xee }
+ }, /* Can be also FIXED in 3G */
+ {
+ SIM_EFCBMIR_FILEID, 8 * 4, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 4, { 0x01, 0xff, 0xee }
+ }, /* 8 records */
+ {
+ SIM_EFCBMI_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 2, { 0x01, 0xff, 0xee }
+ }, /* 8 records */
+ {
+ SIM_EFCBMID_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 2, { 0x01, 0xff, 0x11 }
+ }, /* 8 records */
+ {
+ SIM_EFSMSP_FILEID, 56, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 56, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFIMSI_FILEID, 9, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 9, { 0x0e, 0xff, 0xee }
+ },
};
+static uint8_t get_sfi(const int fileid);
+
This doesn't need forward declaration. Just put the implementation
here. However, I would rename this to something like
fileid_to_short_fileid()
struct sim_imsi {
uint8_t length;
uint8_t imsi[8];
@@ -66,14 +259,283 @@ struct sim_spn {
uint8_t disp_roam;
};
-struct file_info {
- int fileid;
- int length;
- int structure;
- int record_length;
- uint8_t access[3];
- uint8_t file_status;
-};
+static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
+ struct sim_data *sd,
+ uint16_t *length,
+ uint16_t *record_length,
+ uint8_t *records,
+ uint8_t *structure);
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ ofono_sim_passwd_cb_t cb,
+ void *data,
+ uint8_t service);
+
+static void uicc_application_activate_req(GIsiClient *client,
+ void *opaque,
+ unsigned char appl_type,
+ unsigned char aid);
+
Forward declarations should be avoided if at all possible.
+static int sim_applications_get_next_index(struct sim_applications
*sa,
+ int current_app)
+{
+ if (current_app < (MAX_SIM_APPS - 1)) {
+ int i;
+
+ for (i = ++current_app; i < MAX_SIM_APPS; i++) {
+ if (sa->app_list[i] &&
+ (sa->app_type[i] != UICC_APPL_TYPE_UNKNOWN))
Empty line before the if, and if the statement spans multiple lines,
every new line needs an extra indentation.
+ return i;
+ }
+ }
+
+ return NOT_AVAILABLE;
+}
I would refactor this function to return early, if the current_app is
out of range, and not the other way around.
+static uint8_t get_pin_id(struct sim_data *sd,
+ uint8_t passwd_type,
+ int8_t *index)
+{
+ const uint16_t MAX_INDEX = (sizeof(pin_ids)/sizeof(
+ struct sim_passwd_to_pin_id));
+ uint8_t i, pin_id;
+ *index = -1;
+
+ for (i = 0; i < MAX_INDEX; i++) {
+ if (pin_ids[i].passwd_type == passwd_type)
+ *index = i;
+ }
+
+ switch (passwd_type) {
+ case OFONO_SIM_PASSWORD_SIM_PIN:
+ case OFONO_SIM_PASSWORD_SIM_PUK:
+ return sd->pin1_id;
+ case OFONO_SIM_PASSWORD_SIM_PIN2:
+ case OFONO_SIM_PASSWORD_SIM_PUK2:
+ return sd->pin2_id;
+ default:
+
+ if (*index == -1)
+ pin_id = 0;
+ else
+ pin_id = pin_ids[*index].pin_id;
+
+ return pin_id;
+ }
+}
+
+static void update_locked_pin(struct ofono_sim_local *local_sim,
+ uint8_t lock_type, uint8_t pinID)
+{
+ struct sim_data *sd = ofono_sim_get_data((struct ofono_sim *)local_sim);
+
+ switch (lock_type) {
+ case UICC_PIN_VERIFY_NEEDED:
+
+ if (pinID <= sd->pin1_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_SIM_PIN;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
+ sd->passwd_required = TRUE;
+ } else if (pinID == sd->pin2_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_SIM_PIN2;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN2] = TRUE;
+ sd->passwd_required = TRUE;
+ } else if (pinID == upin_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_PHNET_PIN;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PIN] = TRUE;
+ sd->passwd_required = TRUE;
+ }
+
+ break;
+ case UICC_PIN_UNBLOCK_NEEDED:
+
+ if (pinID == sd->pin1_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_SIM_PUK;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK] = TRUE;
+ sd->passwd_required = TRUE;
+ } else if (pinID == sd->pin2_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_SIM_PUK2;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK2] = TRUE;
+ sd->passwd_required = TRUE;
+ } else if (pinID == upin_id) {
+ local_sim->pin_type =
+ OFONO_SIM_PASSWORD_PHNET_PUK;
+ local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PUK] = TRUE;
+ sd->passwd_required = TRUE;
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+static gboolean get_fileid_path(struct ofono_sim *sim,
+ int *mf_path,
+ int *df1_path,
+ int *df2_path,
+ unsigned char *df_len,
+ int fileid)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ switch (fileid) {
+ case SIM_EFPL_FILEID:
+ case SIM_EF_ICCID_FILEID:
+ *mf_path = SIM_MF_FILEID;
+ *df1_path = 0x0000;
+ *df2_path = 0x0000;
+ *df_len = 2;
+ break;
+ case SIM_EFSMSP_FILEID:
+ case SIM_EFSDN_FILEID:
+ case SIM_EFMSISDN_FILEID:
+ *mf_path = SIM_MF_FILEID;
+
+ if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
+ *df1_path = SIM_DFTELECOM_FILEID;
+ else
+ *df1_path = ADF_USIM;
+
+ *df2_path = 0x0000;
+ *df_len = 4;
+ break;
+ case SIM_EFLI_FILEID:
+ case SIM_EFSPN_FILEID:
+ case SIM_EFAD_FILEID:
+ case SIM_EFPNN_FILEID:
+ case SIM_EFOPL_FILEID:
+ case SIM_EFMBDN_FILEID:
+ case SIM_EFMBI_FILEID:
+ case SIM_EFMWIS_FILEID:
+ case SIM_EFSPDI_FILEID:
+ case SIM_EFECC_FILEID:
+ case SIM_EFCBMI_FILEID:
+ case SIM_EFCBMIR_FILEID:
+ case SIM_EFCBMID_FILEID:
+ case SIM_EFIMSI_FILEID:
+ case SIM_EFPHASE_FILEID: /* 3GPP TS 11.11 */
+ case SIM_EFARR_FILEID:
+ case SIM_EF_CPHS_INFORMATION_FILEID:
+ *mf_path = SIM_MF_FILEID;
+
+ if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
+ *df1_path = SIM_DFGSM_FILEID;
+ else
+ *df1_path = ADF_USIM;
+
+ *df2_path = 0x0000;
+ *df_len = 4;
+ break;
+ /* No info */
+ case SIM_EF_CPHS_MBDN_FILEID:
+ case SIM_EF_CPHS_MWIS_FILEID:
+ DBG("======== No path info for %04X", fileid);
+ return FALSE;
+ case SIM_EFADN_FILEID: /* Only for SIM */
+ case SIM_EFEXT1_FILEID: /* Only for SIM */
+ *mf_path = SIM_MF_FILEID;
+ *df1_path = SIM_DFTELECOM_FILEID;
+ *df2_path = 0x0000;
+ *df_len = 4;
+ break;
+ default:
+ *mf_path = SIM_MF_FILEID;
+ *df1_path = SIM_DFTELECOM_FILEID;
+ *df2_path = SIM_DFPHONEBOOK_FILEID;
+ *df_len = 6;
+ break;
+ }
+
+ return TRUE;
+}
+
+static uint8_t get_sfi(const int fileid)
+{
+ uint8_t ret;
+
+ /* SFI list from 3GPP TS 31.102 Annex H */
+ switch (fileid) {
+ case SIM_EFECC_FILEID:
+ ret = 01;
+ break;
+ case SIM_EFLI_FILEID:
+ ret = 02;
+ break;
+ case SIM_EFAD_FILEID:
+ ret = 03;
+ break;
+ case SIM_EFIMSI_FILEID:
+ ret = 07;
+ break;
+ case SIM_EFCBMID_FILEID:
+ ret = 0x0E;
+ break;
+ case SIM_EFPNN_FILEID:
+ ret = 0x19;
+ break;
+ case SIM_EFOPL_FILEID:
+ ret = 0x1A;
+ break;
+ default:
+ ret = UICC_SFI_NOT_PRESENT;
+ break;
+ }
+
+ return ret;
+}
+
+int get_app_id(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("app_id %d", sd->app_id);
+ return sd->app_id;
+ } else
+ return -1;
+}
+
+int get_app_type(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("app_type %d", sd->app_type);
+ return sd->app_type;
+ } else
+ return -1;
+}
+
+int get_client_id(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("client_id %d", sd->client_id);
+ return sd->client_id;
+ } else
+ return -1;
+}
+
+GIsiClient *read_pn_uicc_client(void)
+{
+ return pn_uicc_client;
+}
+
+struct ofono_sim *get_sim(void)
+{
+ return uicc_sim;
+}
How is this API supposed to be used (presumably) by other drivers?
At a minimum, you should keep track of all of the modem references,
and have the other drivers give you their modem reference as a lookup
key.
/* Returns file info */
static gboolean fake_file_info(gpointer user)
@@ -89,29 +551,6 @@ static gboolean fake_file_info(gpointer user)
return FALSE;
}
-static void isi_read_file_info(struct ofono_sim *sim, int fileid,
- ofono_sim_file_info_cb_t cb, void *data)
-{
- int i;
- static struct file_info const info[] = {
- { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
- { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
- };
- int N = sizeof(info) / sizeof(info[0]);
- struct isi_cb_data *cbd;
-
- for (i = 0; i < N; i++) {
- if (fileid == info[i].fileid) {
- cbd = isi_cb_data_new((void *) &info[i], cb, data);
- g_idle_add(fake_file_info, cbd);
- return;
- }
- }
-
- DBG("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
-}
-
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
uint8_t service)
{
@@ -129,7 +568,10 @@ static gboolean check_response_status(const GIsiMessage *msg,
uint8_t msgid,
return FALSE;
}
- if (!g_isi_msg_data_get_byte(msg, 1, &cause) || cause != SIM_SERV_OK) {
+ if ((!g_isi_msg_data_get_byte(msg, 1, &cause) ||
+ cause != SIM_SERV_OK) &&
+ (!g_isi_msg_data_get_byte(msg, 2, &cause) ||
+ cause != UICC_STATUS_OK)) {
PN_UICC has two different causes?
DBG("Request failed: %s",
sim_isi_cause_name(cause));
return FALSE;
}
@@ -141,6 +583,303 @@ static gboolean check_response_status(const GIsiMessage *msg,
uint8_t msgid,
return TRUE;
}
+static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
+ struct sim_data *sd,
+ uint16_t *length,
+ uint16_t *record_length,
+ uint8_t *records, uint8_t *structure)
+{
+ uint8_t fcp;
+ uint8_t fcp_len;
+ uint8_t read = 0;
+ uint8_t id;
+ uint8_t item_len;
+ uint16_t file_id;
+ uint8_t desc;
+ uint8_t coding;
+ uint8_t pin_do_len;
+ uint8_t pin_len;
+ uint8_t pin_tag;
+ uint8_t pin_id;
+ uint8_t pin_tag_pos;
+
+
+ (void)g_isi_sb_iter_get_byte(iter, &fcp, 8);
That cast is not necessary, but you should really check the return value.
+ if (fcp == FCP_TEMPLATE) {
Reduces indentation a lot, if you check that fcp != FCP_TEMPLATE, and
goto some 'out' label.
+ (void) g_isi_sb_iter_get_byte(iter, &fcp_len,
9);
+ while (read < fcp_len) {
+ (void) g_isi_sb_iter_get_byte(iter, &id, read + 10);
+ (void) g_isi_sb_iter_get_byte(iter, &item_len,
+ read + 11);
+
+ switch (id) {
+ case FCP_FILE_SIZE:
+ if (item_len == 2) {
+ g_isi_sb_iter_get_word(iter, length,
+ read + 10 + 2);
+ }
+ break;
+ case FCP_FILE_ID:
+
+ if (item_len == 2) {
+ g_isi_sb_iter_get_word(iter, &file_id,
+ read + 10 + 2);
+ }
+ break;
+ case FCP_FILE_DESC:
+ if (item_len >= 2) {
+ g_isi_sb_iter_get_byte(iter, &desc,
+ read + 10 + 2);
+ g_isi_sb_iter_get_byte(iter, &coding,
+ read + 10 + 3);
+ }
+
+ if (item_len >= 4) {
+ g_isi_sb_iter_get_word(iter,
+ record_length,
+ read + 10 + 4);
+ g_isi_sb_iter_get_byte(iter, records,
+ read + 10 + 6);
+ }
+ break;
+ case FCP_PIN_STATUS:
+ g_isi_sb_iter_get_byte(iter, &pin_do_len,
+ read + 10 + 3);
+ pin_tag_pos = read + 10 + 4 + pin_do_len;
+ g_isi_sb_iter_get_byte(iter, &pin_tag,
+ pin_tag_pos);
+
+ while (pin_tag == 0x83) {
+
+ g_isi_sb_iter_get_byte(iter, &pin_len,
+ pin_tag_pos + 1);
+ g_isi_sb_iter_get_byte(iter, &pin_id,
+ pin_tag_pos + 2);
+
+ pin_tag_pos += 2 + pin_len;
+ g_isi_sb_iter_get_byte(iter, &pin_tag,
+ pin_tag_pos);
+
+ if ((0x01 <= pin_id) &&
+ (pin_id <= 0x08))
+ sd->pin1_id = pin_id;
+ else if ((0x81 <= pin_id) &&
+ (pin_id <= 0x88))
+ sd->pin2_id = pin_id;
+ read += item_len + 2;
+ }
+ break;
+ case FCP_FILE_SECURITY_ARR:
+ case FCP_FILE_SECURITY_COMPACT:
+ case FCP_FILE_SECURITY_EXPANDED:
+
+ /* Not implemented, using
+ * static access rules as these
+ * are used only for caching
+ * See ETSI TS 102 221, ch
+ * 11.1.1.4.7 and
+ * Annexes E,F and G
+ */
+ case FCP_FILE_LIFECYCLE:
+ default:
+ DBG("FCP id %02X not supported", id);
+ break;
+ }
+
+ /*Data length + id size + len size */
+ read += item_len + 2;
+ }
+ }
+ if ((desc & 7) == 1)
+ *structure = OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
+ else if ((desc & 7) == 2)
+ *structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
+ else if ((desc & 7) == 6)
+ *structure = OFONO_SIM_FILE_STRUCTURE_CYCLIC;
+}
+
+static void isi_file_info_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_file_info_cb_t cb = cbd->cb;
+ uint16_t length = 0;
+ uint16_t record_length = 0;
+ uint8_t structure = -1;
+ uint8_t records = 0;
+ uint16_t file_id = 0;
+ uint8_t access[3] = {0, 0, 0};
+ uint8_t item_len = 0;
+ gboolean everything_ok = FALSE;
+ /*Access is read from static file info*/
+ struct file_info const *info = cbd->user;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_FILE_INFO))
+ goto error;
+
+ if (info != NULL) {
+ access[0] = info->access[0];
+ access[1] = info->access[1];
+ access[2] = info->access[2];
+ }
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FCI:
+ DBG("UICC_SB_FCI");
+ everything_ok = TRUE;
+
+ switch (sd->app_type) {
+ case UICC_APPL_TYPE_UICC_USIM:
+ DBG("UICC_APPL_TYPE_UICC_USIM");
+ handle_app_uicc_usim(&iter, sd,
+ &length, &record_length,
+ &records, &structure);
+
+ break;
+ case UICC_APPL_TYPE_ICC_SIM:
+ DBG("UICC_APPL_TYPE_ICC_SIM");
+ g_isi_sb_iter_get_word(&iter, &length, 10);
+ g_isi_sb_iter_get_word(&iter, &file_id, 12);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 16);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 17);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 18);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &item_len, 20);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &structure,
+ 21);
+
+ if (item_len == 2)
+ (void)g_isi_sb_iter_get_byte(&iter,
+ (uint8_t *)&record_length,
+ 22);
+
+ break;
+ default:
+ DBG("UICC application type %d not supported",
+ sd->app_type);
+ break;
+ }
+
+ break;
+ default:
+ DBG("Skipping SB");
+ break;
+ }
+
+ if (g_isi_sb_iter_next(&iter) == FALSE)
+ goto error;
+ }
+
+ if (everything_ok) {
+ CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
+ access, '\n', cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading file info");
+ CALLBACK_WITH_FAILURE(cb, 0, 0, 0, access, '\n', cbd->data);
+}
+
+static void isi_read_file_info(struct ofono_sim *sim, int fileid,
+ ofono_sim_file_info_cb_t cb, void *data)
+{
+ int i;
+ static struct file_info const info[] = {
+ { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
+ { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
+ };
+ int N = sizeof(info) / sizeof(info[0]);
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd;
+
+ if ((sd != NULL) && g_isi_client_resource(sd->client) == PN_UICC) {
+ /* Prepare for static file info used for access rights */
+ int i;
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+
+ N = sizeof(static_file_info) / sizeof(static_file_info[0]);
+ cbd = isi_cb_data_new(NULL, cb, data);
+ DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
+
+ for (i = 0; i < N; i++) {
+ if (fileid == static_file_info[i].fileid &&
+ cbd != NULL) {
+ cbd->user = (void *) &static_file_info[i];
+ continue;
+ }
+ }
+ if (!get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ g_free(cbd);
+ goto error;
+ }
+ if (cbd) {
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_FILE_INFO,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1*/
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid), /* Elementary file short id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF,
+ };
+ g_isi_client_send(sd->client, msg, sizeof(msg),
+ isi_file_info_resp, cbd, g_free);
+ return;
+ }
+ } else {
+ for (i = 0; i < N; i++) {
+ if (fileid == info[i].fileid) {
+ cbd = isi_cb_data_new((void *) &info[i], cb,
+ data);
+ g_idle_add(fake_file_info, cbd);
+ return;
+ }
+ }
+
+ }
+error:
+ DBG("Fileid %04X not implemented", fileid);
+ CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
+}
+
static void spn_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -234,32 +973,142 @@ static gboolean isi_read_iccid(struct ofono_sim *sim, struct
isi_cb_data *cbd)
read_iccid_resp_cb, cbd, g_free);
}
+static void isi_read_file_transparent_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
+ uint32_t filelen = 0;
+ unsigned char filedata[256] = { 0xff };
+ gboolean everything_ok = FALSE;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_READ_TRANSPARENT))
+ goto error;
+
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FILE_DATA:
+ g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+ memmove(&filedata, iter.start + 8, filelen);
+ everything_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ if (everything_ok) {
+ DBG("Transparent EF read: 1st byte %02x, len %d",
+ filedata[0], filelen);
+ CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading transparent EF");
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
static void isi_read_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length,
ofono_sim_read_cb_t cb, void *data)
{
+ struct sim_data *sd = ofono_sim_get_data(sim);
struct isi_cb_data *cbd;
gboolean done;
cbd = isi_cb_data_new(sim, cb, data);
- if (cbd == NULL)
+
+ if (cbd == NULL || sd == NULL)
goto error;
- switch (fileid) {
- case SIM_EFSPN_FILEID:
- done = isi_read_spn(sim, cbd);
- break;
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+
+ DBG("File ID=%04X, client %d, AID %d",
+ fileid, sd->client_id, sd->app_id);
+
+ if (get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_READ_TRANSPARENT,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 3, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xff,
+ 0,
+ 8, /*Sub block length*/
+ 0, 0, 0, /* Filler */
+ sd->client_id,
+ /* Subblock 2*/
+ UICC_SB_TRANSPARENT >> 8,
+ UICC_SB_TRANSPARENT & 0xff,
+ 0, /*Sub block length*/
+ 8, /*Sub block length*/
+ 0, /*File offset (0=beginning)*/
+ 0, /*File offset (0=beginning)*/
+ 0, /*Data amount (0=all)*/
+ 0, /*Data amount (0=all)*/
+ /* Subblock 3 */
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /* Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid),/*Elementary file short id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF
+ };
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ isi_read_file_transparent_resp, cbd, g_free);
+ return;
+ }
+ goto error;
- case SIM_EF_ICCID_FILEID:
- done = isi_read_iccid(sim, cbd);
- break;
+ } else {
+ switch (fileid) {
+ case SIM_EFSPN_FILEID:
+ done = isi_read_spn(sim, cbd);
+ break;
- default:
- done = FALSE;
- }
+ case SIM_EF_ICCID_FILEID:
+ done = isi_read_iccid(sim, cbd);
+ break;
- if (done)
- return;
+ default:
+ done = FALSE;
+ }
+
+ if (done)
+ return;
+ }
DBG("Fileid %04X not implemented", fileid);
@@ -268,12 +1117,125 @@ error:
g_free(cbd);
}
-static void isi_read_file_linear(struct ofono_sim *sim, int fileid,
- int record, int length,
- ofono_sim_read_cb_t cb, void *data)
+static void isi_read_file_linear_fixed_resp(const GIsiMessage *msg, void *data)
{
- DBG("Fileid %04X not implemented", fileid);
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
+ uint32_t filelen = 0;
+ unsigned char filedata[256] = { 0xff };
+ gboolean everything_ok = FALSE;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_READ_LINEAR_FIXED))
+ goto error;
+
+ everything_ok = FALSE;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FILE_DATA:
+ g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+ memmove(&filedata, iter.start + 8, filelen);
+ everything_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ if (everything_ok) {
+ DBG("Linear fixed EF read: 1st byte %02x, len %d",
+ filedata[0], filelen);
+ CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading linear fixed EF");
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
+static void isi_read_file_linear(struct ofono_sim *sim,
+ int fileid,
+ int record,
+ int rec_length,
+ ofono_sim_read_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);
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+ DBG("File ID=%04X, record %d, client %d AID %d",
+ fileid, record, sd->client_id, sd->app_id);
+ if (!get_fileid_path(sim, &mf_path,
+ &df1_path, &df2_path, &df_len, fileid))
+ goto error;
+ if ((cbd != NULL) && (sd != NULL)) {
+
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_READ_LINEAR_FIXED,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 3, /*number of subblocks*/
+ /* Subblock 1*/
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xff,
+ 0,
+ 8, /*Sub block length */
+ 0, 0, 0, /* Filler */
+ sd->client_id,
+ /* Subblock 2 */
+ UICC_SB_LINEAR_FIXED >> 8,
+ UICC_SB_LINEAR_FIXED & 0xff,
+ 0, /*Sub block length*/
+ 8, /*Sub block length*/
+ record, /*Record*/
+ 0, /*Record offset (0=beginning)*/
+ rec_length & 0xff, /*Data amount (0=all)*/
+ 0, /*Filler*/
+ /* Subblock 3*/
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid), /* Elementary file short file id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF
+ };
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ isi_read_file_linear_fixed_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("Not implemented (fileid = %04x)", fileid);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+ g_free(cbd);
}
static void isi_read_file_cyclic(struct ofono_sim *sim, int fileid,
@@ -293,13 +1255,123 @@ static void isi_write_file_transparent(struct ofono_sim *sim, int
fileid,
CALLBACK_WITH_FAILURE(cb, data);
}
+static void write_file_linear_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_write_cb_t cb = cbd->cb;
+ DBG("");
+
+ if (check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_UPDATE_LINEAR_FIXED))
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+}
+
static void isi_write_file_linear(struct ofono_sim *sim, int fileid,
int record, int length,
const unsigned char *value,
ofono_sim_write_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);
+
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+ size_t i = 0;
+ size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
+ size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
+ uint8_t *fill_data = g_try_malloc0(fill_count);
+
+ DBG("");
+
+ if (!fill_data && fill_count > 0) {
+ g_free(fill_data);
+ goto error;
+ }
+ for (i = 0; i < fill_count; i++)
+ fill_data[i] = 0x00;
+
+ if (!sd->app_id || !sd->client_id || !sd || !sd->client ||
+ !cbd) {
+ DBG("Parameter error");
+ g_free(fill_data);
+ goto error;
+ }
+
+ if (get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ uint8_t msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_UPDATE_LINEAR_FIXED,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED,
+ 0x00, 0x00, /* fillers */
+ 0x04, /* nro of sub blocks */
+ /* 1st subblock */
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xFF,
+ 0x00, 0x08, /* subblock length */
+ 0x00, 0x00, 0x00, /* fillers */
+ sd->client_id,
+ /* 2nd subblock */
+ UICC_SB_LINEAR_FIXED >> 8,
+ UICC_SB_LINEAR_FIXED & 0xFF,
+ 0x00, 0x08, /* subblock length */
+ record, /* the record in the file*/
+ 0x00, /* record offset (0 == beginning) */
+ 0x00, /* data amount, used only for reading */
+ 0x00, /* filler */
+ /* 3th subblock */
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xFF,
+ 0x00, 0x10, /* subblock length */
+ fileid >> 8, /* elementary file id */
+ fileid & 0xFF,
+ get_sfi(fileid),
+ 0x00, /* filler */
+ df_len, /* path length */
+ 0x00, /* filler */
+ mf_path >> 8, /* DF Path MF */
+ mf_path & 0xFF,
+ df1_path >> 8, /* DF Path */
+ df1_path & 0xFF,
+ df2_path >> 8, /* DF Path */
+ df2_path & 0xFF,
+ /* 4nd subblock */
+ UICC_SB_FILE_DATA >> 8,
+ UICC_SB_FILE_DATA & 0xFF,
+ sb_file_data_legth >> 8, /* subblock length */
+ sb_file_data_legth & 0xFF,
+ length >> 24, /* data length */
+ length >> 16, /* need to be shifted */
+ length >> 8,
+ length & 0xFF,
+ };
+
+ struct iovec iov[3] = {
+ { msg, sizeof(msg) },
+ { (uint8_t *)value, length },
+ { fill_data, fill_count },
+ };
+
+ if (!g_isi_client_vsend_with_timeout(sd->client, iov,
+ 3, SIM_TIMEOUT, write_file_linear_cb,
+ cbd, g_free)) {
+ g_free(fill_data);
+ goto error;
+ }
+
+ g_free(fill_data);
+ return;
+ }
+ }
DBG("Fileid %04X not implemented", fileid);
+error:
CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
}
static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
@@ -309,10 +1381,53 @@ static void isi_write_file_cyclic(struct ofono_sim *sim, int
fileid,
DBG("Fileid %04X not implemented", fileid);
CALLBACK_WITH_FAILURE(cb, data);
}
-
-static void imsi_resp_cb(const GIsiMessage *msg, void *data)
+static void uicc_read_imsi_resp(const struct ofono_error *error,
+ const unsigned char *data,
+ int len,
+ void *user)
{
- struct isi_cb_data *cbd = data;
+ struct isi_cb_data *cbd = user;
+ ofono_sim_imsi_cb_t cb = cbd->cb;
+ /* For coding see TS 24.008 */
+ char imsi[SIM_MAX_IMSI_LENGTH + 1];
+ int i = 1; /*Skip length, the 1st byte*/
+ int j = 0;
+ int octets;
+
+ if (data == NULL)
+ goto error;
+
+ octets = data[0];
+
+ if (octets != 8 || octets > len)
+ goto error;
+
+ /* Ignore the low-order semi-octet of the first byte */
+ imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
+
+ for (i++, j++; i - 1 < octets && j < SIM_MAX_IMSI_LENGTH; i++) {
+ char nibble;
+ imsi[j++] = (data[i] & 0x0F) + '0';
+ nibble = (data[i] & 0xF0) >> 4;
+
+ if (nibble != 0x0F)
+ imsi[j++] = nibble + '0';
+ }
+
+ imsi[j] = '\0';
+ DBG("IMSI %s", imsi);
+ CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
+ goto out;
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+out:
+ g_free(cbd);
+ return;
+}
+
+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;
@@ -321,9 +1436,6 @@ static void imsi_resp_cb(const GIsiMessage *msg, void *data)
char imsi[SIM_MAX_IMSI_LENGTH + 1];
size_t i, j;
- if (!check_response_status(msg, SIM_IMSI_RESP_READ_IMSI, READ_IMSI))
- goto error;
-
if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
goto error;
@@ -352,16 +1464,24 @@ static void isi_read_imsi(struct ofono_sim *sim,
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ size_t len;
const uint8_t msg[] = {
SIM_IMSI_REQ_READ_IMSI,
READ_IMSI
};
- size_t len = sizeof(msg);
if (cbd == NULL || sd == NULL)
goto error;
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ isi_read_file_transparent(sim, SIM_EFIMSI_FILEID, 0, 9,
+ uicc_read_imsi_resp, cbd);
+ return;
+ }
+ len = sizeof(msg);
+
+
if (g_isi_client_send(sd->client, msg, len, imsi_resp_cb, cbd, g_free))
return;
@@ -370,6 +1490,976 @@ error:
g_free(cbd);
}
+static void uicc_application_activate_resp(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ uint8_t *msg_data = (uint8_t *)g_isi_msg_data(msg);
+
+ if (!check_response_status(msg, UICC_APPLICATION_RESP,
+ UICC_APPL_HOST_ACTIVATE))
+ return;
+
+ if ((msg_data[2] == UICC_STATUS_OK) ||
+ (msg_data[2] == UICC_STATUS_APPL_ACTIVE)) {
+ if (!sd->uicc_app_started) {
+ sd->app_id = sd->trying_app_id;
+ sd->app_type = sd->trying_app_type;
+ sd->uicc_app_started = TRUE;
+ DBG("UICC application activated");
+ ofono_sim_inserted_notify(sim, TRUE);
+ ofono_sim_register(sim);
+ g_free(sim_application_list_p);
+ }
+ } else {
+ int i = sim_applications_get_next_index(
+ sim_application_list_p, sd->trying_app_id);
+
+ if (i == NOT_AVAILABLE) {
+ g_free(sim_application_list_p);
+ return;
+ }
+
+ DBG("Activation Error, trying to activate APP with ID:%d", i);
+ uicc_application_activate_req(sd->client, sim,
+ sim_application_list_p->app_type[i],
+ sim_application_list_p->app_list[i]);
+ return;
+ }
+
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_CLIENT: {
+ guint8 client = 0;
+ g_isi_sb_iter_get_byte(&iter, &client, 7);
+ DBG("Client id %d", client);
+ sd->client_id = client;
+ break;
+ }
+ case UICC_SB_FCI:
+ DBG("UICC_SB_FCI");
+
+ if (sd->app_type == UICC_APPL_TYPE_UICC_USIM) {
+ uint16_t length, record_length;
+ uint8_t records, structure;
+ handle_app_uicc_usim(&iter, sd, &length,
+ &record_length, &records,
+ &structure);
+ }
+
+ break;
+ case UICC_SB_CHV:
+ DBG("UICC_SB_CHV");
+
+ if (sd->app_type == UICC_APPL_TYPE_ICC_SIM) {
+ uint8_t chv_id = 0, pin_id = 0;
+ (void) g_isi_sb_iter_get_byte(&iter,
+ &chv_id, 4);
+ (void) g_isi_sb_iter_get_byte(&iter,
+ &pin_id, 5);
+ DBG("UICC_APPL_TYPE_UICC_SIM");
+
+ if (chv_id == 1)
+ sd->pin1_id = pin_id;
+ else if (chv_id == 2)
+ sd->pin2_id = pin_id;
+ }
+
+ break;
+ default:
+ DBG("Skipping sub-block: %s (%zu bytes)",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+
+ (void)g_isi_sb_iter_next(&iter);
+ }
+}
+
+static void uicc_application_activate_req(GIsiClient *client,
+ void *opaque,
+ unsigned char appl_type,
+ unsigned char aid)
+{
+ const unsigned char msg[] = {
+ UICC_APPLICATION_REQ,
+ UICC_APPL_HOST_ACTIVATE,
+ 2, /* number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_APPLICATION >> 8,
+ UICC_SB_APPLICATION & 0xff,
+ 0, /*subblock length*/
+ 8, /*subblock length*/
+ 0, /*filler*/
+ 0, /*filler*/
+ appl_type,
+ aid,
+ /* Subblock 2 */
+ UICC_SB_APPL_INFO >> 8,
+ UICC_SB_APPL_INFO & 0xff,
+ 0, /*subblock length*/
+ 8, /*subblock length*/
+ 0, /*filler*/
+ 0, /*filler*/
+ 0, /*filler*/
+ /* whether the application initialization procedure
+ * will follow the activation or not */
+ UICC_APPL_START_UP_INIT_PROC
+ };
+
+ DBG("Appl type %d, AID %d", appl_type, aid);
+
+ g_isi_client_send_with_timeout(
+ client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_application_activate_resp, opaque, NULL);
+}
+
+static void uicc_application_list_resp(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ gboolean everything_ok = TRUE;
+ int index = NOT_AVAILABLE;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ if (!check_response_status(msg, UICC_APPLICATION_RESP,
+ UICC_APPL_LIST)) {
+ uint8_t status = 0;
+
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ if (status != UICC_STATUS_FAIL)
+ return;
+ everything_ok = FALSE;
+ }
+
+ sim_application_list_p = g_try_new0(struct sim_applications, 1);
+
+ if (everything_ok) {
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(
+ g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_APPL_DATA_OBJECT: {
+ guint8 appl_id = -1;
+ guint8 appl_type = -1;
+ guint8 status = -1;
+ gboolean ret;
+ ret = g_isi_sb_iter_get_byte(
+ &iter, &appl_type, 6);
+ ret = g_isi_sb_iter_get_byte(
+ &iter, &appl_id, 7);
+ (void) g_isi_sb_iter_get_byte(
+ &iter, &status, 8);
+ DBG("Appl type=%d, Appl id=%d, Appl
status=%d",
+ appl_type, appl_id, status);
+
+ sim_application_list_p->app_list[appl_id] =
+ appl_id;
+ sim_application_list_p->app_type[appl_id] =
+ appl_type;
+ break;
+ }
+ default:
+ DBG("Skipping sub-block: %s (%zu bytes)",
+ uicc_subblock_name(
+ g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+ }
+
+ if (!sd->uicc_app_started) {
+ index = sim_applications_get_next_index(sim_application_list_p,
+ NOT_ACTIVATED);
+
+ if (index != NOT_AVAILABLE) {
+ DBG("Activating APP index:%d", index);
+ sd->trying_app_id =
+ sim_application_list_p->app_list[index];
+ sd->trying_app_type =
+ sim_application_list_p->app_type[index];
+ DBG("Activating APP ID: %d APP type: %d",
+ sd->trying_app_id, sd->trying_app_type);
+ uicc_application_activate_req(sd->client, sim,
+ sim_application_list_p->app_type[index],
+ sim_application_list_p->app_list[index]);
+ } else
+ g_free(sim_application_list_p);
+ }
+}
+
+static void uicc_application_list_req(GIsiClient *client,
+ void *opaque)
+{
+ const unsigned char msg[] = {
+ UICC_APPLICATION_REQ,
+ UICC_APPL_LIST,
+ 0 /* number of subblocks*/
+ };
+ DBG("");
+
+ g_isi_client_send_with_timeout(
+ client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_application_list_resp, opaque, NULL);
+}
+
+static void uicc_pin_enter_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct ofono_error error;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+ uint8_t status = 0, sbcount = 0;
+
+ if (msg == NULL)
+ goto error;
Looks reasonable...
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ if (status == UICC_STATUS_OK) {
+ sd->passwd_required = FALSE;
+ error.type = OFONO_ERROR_TYPE_NO_ERROR;
+ error.error = 0;
+ goto out;
+ }
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
Huh? You ended up here because msg == NULL!
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
Why aren't these in some PN_UICC related enum?
+ DBG("Authentication method
blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status &
0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ error.type = OFONO_ERROR_TYPE_FAILURE;
+ error.error = 1;
+out:
+ cb(&error, cbd->data);
Could you use the CALLBACK_WITH_* macros here instead?
+}
+
+static void uicc_pin_enter(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);
+ sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
+ DBG("PIN=%s PINID=%02x", passwd, sd->current_pin_id);
+
+ if (cbd && sd) {
+ unsigned char pinlen = strlen(passwd);
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ UICC_PIN_VERIFY,
+ sd->app_id,
+ 0, /* Filler */
+ 0, /* Filler */
+ 0, /* Filler */
+ 1, /* number of subblocks */
+ /* Subblock 1 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /* Max length */
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_OLD, /* PIN qualifier */
+ pinlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+
+ memmove(&msg[14], passwd, pinlen);
We have typically used struct iovec and the vsend() API for these
types of messages.
+ g_isi_client_send_with_timeout(sd->client, msg,
sizeof(msg),
+ SIM_TIMEOUT, uicc_pin_enter_resp, cbd,
+ g_free);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+}
+
+enum ofono_sim_password_type passwd_type_for_query =
+ OFONO_SIM_PASSWORD_SIM_PIN;
Just put OFONO_SIM_PASSWORD_SIM_PIN directly in those two places where
you end up using this.
+static void uicc_pin_prompt_resp(const GIsiMessage *msg, void
*data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_passwd_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *)local_sim);
+
+ unsigned char lock_type = -1;
+ GIsiSubBlockIter iter;
+ uint8_t status = UICC_STATUS_UNKNOWN;
+ uint8_t pin_attempts = -1;
+ uint8_t puk_attempts = -1;
+
+ if (!check_response_status(msg, UICC_PIN_RESP,
+ UICC_PIN_PROMPT_VERIFY) && !check_response_status(msg,
+ UICC_PIN_RESP, UICC_PIN_INFO))
+ goto error;
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ sd->pin_state_received = TRUE;
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ } else if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_INFO)) {
+ uint8_t sbcount = 0;
+
+ sd->pin_state_received = TRUE;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(
+ &iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_PIN_INFO:
+ g_isi_sb_iter_get_byte(&iter, &status, 4);
+ g_isi_sb_iter_get_byte(&iter,
+ &pin_attempts, 5);
+ g_isi_sb_iter_get_byte(&iter,
+ &puk_attempts, 6);
+ DBG("Status=%s, PIN attempts=%d, \
+ PUK attempts=%d",
+ uicc_status_name(status),
+ pin_attempts, puk_attempts);
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+ }
+
+ if ((status == UICC_STATUS_OK) ||
+ (status == UICC_STATUS_PIN_ENABLED)) {
+ /* PIN query on, indication should tell
+ * if it is verified or not
+ */
+ if (pin_attempts == 0) {
+ DBG("PIN blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ } else {
+ DBG("PIN query enabled");
+ update_locked_pin(local_sim,
+ UICC_PIN_VERIFY_NEEDED,
+ sd->current_pin_id);
+ }
+
+ lock_type = local_sim->pin_type;
+ } else if (status == UICC_STATUS_PIN_DISABLED) {
+ if (pin_attempts == 0) {
+ DBG("PIN blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ lock_type = local_sim->pin_type;
+ } else {
+ DBG("PIN query disabled");
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] =
+ FALSE;
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] =
+ FALSE;
+ lock_type = OFONO_SIM_PASSWORD_NONE;
+ }
+ }
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ uicc_pin_prompt(cbd->user,
+ passwd_type_for_query,
+ cb,
+ cbd->data,
+ UICC_PIN_INFO);
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
+ return;
+error:
+ DBG("PIN prompt verify failed");
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ ofono_sim_passwd_cb_t cb,
+ void *data,
+ uint8_t service)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ int8_t index;
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+ DBG("PINID = %02x", sd->current_pin_id);
+
+ if ((cbd) && (sd) && (sd->current_pin_id)) {
Check for NULL here, and for zero pin_id, and return with error.
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_PIN_REF >> 8,
+ UICC_SB_PIN_REF & 0xff,
+ 0, /*Sub block length.*/
+ 8,
+ sd->current_pin_id, /*PIN ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0 /*Filler*/
+ };
+ g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SIM_TIMEOUT, uicc_pin_prompt_resp, cbd,
+ g_free);
+ } else {
+ DBG("PIN info query failed");
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ g_free(cbd);
+ }
+}
+
+static void uicc_passwd_state_query(struct ofono_sim *sim,
+ ofono_sim_passwd_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct ofono_sim_local *local_sim = (struct ofono_sim_local *)sim;
+
+ if (sd->pin_state_received) {
+ int lock_type = OFONO_SIM_PASSWORD_NONE;
+
+ if (sd->passwd_required) {
+ /* These should be in priority order, highest last */
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PIN;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN2] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PIN2;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PIN] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_PHNET_PIN;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PUK;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK2] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PUK2;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PUK] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_PHNET_PUK;
+ }
+
+ DBG("UICC lock type=%d", lock_type);
+ CALLBACK_WITH_SUCCESS(cb, lock_type, data);
+ } else {
+ if (sd->uicc_app_started) {
+ /* No indication received but UICC app is
+ * started, let's query the state
+ */
+ DBG("Querying PIN info");
+ uicc_pin_prompt(sim, passwd_type_for_query,
+ cb, data, UICC_PIN_PROMPT_VERIFY);
+ return;
+ }
+
+ DBG("No UICC_PIN_IND received");
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ }
+}
+
+static void uicc_pin_enable_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_DISABLE) &&
+ !check_response_status(msg, UICC_PIN_RESP,
+ UICC_PIN_ENABLE))
+ goto error;
+
+ DBG("PIN lock/unlock succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status &
0xf);
+
+ break;
+ }
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ DBG("PIN lock/unlock failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void uicc_pin_enable(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 sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ int8_t index;
+ unsigned char service = 0;
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+
+ DBG("Lock=%d, PIN code=%s, PIN ID =%d",
+ enable, passwd, sd->current_pin_id);
+ if (enable) {
+ DBG("Enabling PIN");
+ service = UICC_PIN_ENABLE;
+ } else {
+ DBG("Disabling PIN");
+ service = UICC_PIN_DISABLE;
+ }
+ if ((cbd) && (sd) && (sd->current_pin_id)) {
+
+ unsigned char pinlen = strlen(passwd);
+
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /*Max length*/
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_OLD, /* PIN qualifier */
+ pinlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+ memmove(&msg[14], passwd, pinlen);
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_pin_enable_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("Error");
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+ return;
+}
+
+static void uicc_pin_change_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_CHANGE))
+ goto error;
+
+ DBG("PIN change succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+error:
Same as above, this can't be right that you end up decoding the
message when there is a response reporting failure?
Cheers,
Aki