isimodem: Add baseline for UICC driver

This commit is contained in:
Aki Niemi 2011-06-16 14:47:50 +03:00
parent 6f6f7f39e0
commit 8cbb0252b4
4 changed files with 503 additions and 0 deletions

View File

@ -53,6 +53,7 @@ static int isimodem_init(void)
isi_gprs_init();
isi_gprs_context_init();
isi_audio_settings_init();
isi_uicc_init();
return 0;
}
@ -75,6 +76,7 @@ static void isimodem_exit(void)
isi_gprs_exit();
isi_gprs_context_exit();
isi_audio_settings_exit();
isi_uicc_exit();
}
OFONO_PLUGIN_DEFINE(isimodem, "PhoNet / ISI modem driver", VERSION,

View File

@ -66,3 +66,6 @@ extern void isi_gprs_context_exit(void);
extern void isi_audio_settings_init(void);
extern void isi_audio_settings_exit(void);
extern void isi_uicc_init(void);
extern void isi_uicc_exit(void);

492
drivers/isimodem/uicc.c Normal file
View File

@ -0,0 +1,492 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) ST-Ericsson SA 2011.
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
*
* 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#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 "isimodem.h"
#include "isiutil.h"
#include "sim.h"
#include "uicc.h"
#include "debug.h"
#define USIM_APP_DEDICATED_FILE 0x7FFF
#define MAX_SIM_APPS 8
enum uicc_flag {
UICC_FLAG_APP_STARTED = 1 << 0,
UICC_FLAG_PIN_STATE_RECEIVED = 1 << 1,
UICC_FLAG_PASSWD_REQUIRED = 1 << 2,
};
struct sim_data {
GIsiClient *client;
unsigned flags;
int app_id;
int app_type;
uint8_t client_id;
};
static GHashTable *g_modems;
struct file_info {
int fileid;
int length;
int structure;
int record_length;
uint8_t access[3];
uint8_t file_status;
};
static const struct file_info static_file_info[] = {
{ SIM_EFSPN_FILEID, 17, 0, 0, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EF_ICCID_FILEID, 10, 0, 10, { 0x0f, 0xff, 0xee }, 1 },
{ SIM_EFPL_FILEID, 1, 0, 1, { 0x0f, 0xff, 0xff }, 1 },
{ SIM_EFLI_FILEID, 1, 0, 1, { 0x0f, 0xff, 0xff }, 1 },
{ SIM_EFMSISDN_FILEID, 28, 1, 28, { 0x01, 0xff, 0xee }, 1 },
{ SIM_EFAD_FILEID, 20, 0, 20, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFPHASE_FILEID, 1, 0, 1, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFPNN_FILEID, 4 * 18, 1, 18, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFOPL_FILEID, 4 * 24, 1, 24, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFMBI_FILEID, 5, 1, 5, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFMWIS_FILEID, 6, 1, 6, { 0x01, 0xff, 0xee }, 1 },
{ SIM_EFSPDI_FILEID, 64, 0, 64, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFECC_FILEID, 5 * 3, 0, 3, { 0x0e, 0xff, 0xee }, 1 },
{ SIM_EFCBMIR_FILEID, 8 * 4, 0, 4, { 0x01, 0xff, 0xee }, 1 },
{ SIM_EFCBMI_FILEID, 8 * 2, 0, 2, { 0x01, 0xff, 0xee }, 1 },
{ SIM_EFCBMID_FILEID, 8 * 2, 0, 2, { 0x01, 0xff, 0x11 }, 1 },
{ SIM_EFSMSP_FILEID, 56, 1, 56, { 0x01, 0xff, 0xee }, 1 },
{ SIM_EFIMSI_FILEID, 9, 0, 9, { 0x0e, 0xff, 0xee }, 1 },
};
static gboolean check_resp(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", g_isi_msg_strerror(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 != UICC_STATUS_OK) {
DBG("Request failed: %s", uicc_status_name(cause));
return FALSE;
}
if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
DBG("Unexpected service: 0x%02X (0x%02X)", type, service);
return FALSE;
}
return TRUE;
}
static void uicc_read_file_info(struct ofono_sim *sim, int fileid,
ofono_sim_file_info_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
}
static void uicc_read_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length,
ofono_sim_read_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void uicc_read_file_linear(struct ofono_sim *sim, int fileid, int record,
int rec_length, ofono_sim_read_cb_t cb,
void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void uicc_read_file_cyclic(struct ofono_sim *sim, int fileid,
int record, int length,
ofono_sim_read_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void uicc_write_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length,
const unsigned char *value,
ofono_sim_write_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_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)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_write_file_cyclic(struct ofono_sim *sim, int fileid, int length,
const unsigned char *value,
ofono_sim_write_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_read_imsi(struct ofono_sim *sim,
ofono_sim_imsi_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void uicc_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void uicc_send_passwd(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb,
void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void uicc_reset_passwd(struct ofono_sim *sim, const char *puk,
const char *passwd, ofono_sim_lock_unlock_cb_t cb,
void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_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)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_lock(struct ofono_sim *sim, enum ofono_sim_password_type type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_query_locked(struct ofono_sim *sim,
enum ofono_sim_password_type type,
ofono_sim_locked_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void pin_ind_cb(const GIsiMessage *msg, void *data)
{
DBG("%s", uicc_message_id_name(g_isi_msg_id(msg)));
}
static void card_ind_cb(const GIsiMessage *msg, void *data)
{
DBG("%s", uicc_message_id_name(g_isi_msg_id(msg)));
}
static void uicc_ind_cb(const GIsiMessage *msg, void *data)
{
DBG("%s", uicc_message_id_name(g_isi_msg_id(msg)));
}
static void app_ind_cb(const GIsiMessage *msg, void *data)
{
DBG("%s", uicc_message_id_name(g_isi_msg_id(msg)));
}
static gboolean decode_data_object(uint8_t *buf, size_t len)
{
DBG("template=0x%02X length=%u bytes AID=0x%02X",
buf[0], buf[1], buf[2]);
return TRUE;
}
struct data_object {
uint16_t filler;
uint8_t type;
uint8_t id;
uint8_t status;
uint8_t len;
};
static void uicc_app_list_resp(const GIsiMessage *msg, void *data)
{
struct ofono_sim *sim = data;
struct sim_data *sd = ofono_sim_get_data(sim);
GIsiSubBlockIter iter;
uint8_t sb;
struct data_object *app;
size_t len = sizeof(struct data_object);
uint8_t *obj;
if (!check_resp(msg, UICC_APPLICATION_RESP, UICC_APPL_LIST))
goto fail;
if (!g_isi_msg_data_get_byte(msg, 5, &sb))
goto fail;
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sb);
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
if (g_isi_sb_iter_get_id(&iter) != UICC_SB_APPL_DATA_OBJECT)
continue;
if (!g_isi_sb_iter_get_struct(&iter, (void **) &app, len, 4))
goto fail;
if (!g_isi_sb_iter_get_struct(&iter, (void **) &obj, app->len,
4 + len))
goto fail;
DBG("type=0x%02X id=0x%02X status=0x%02X length=%u bytes",
app->type, app->id, app->status, app->len);
decode_data_object(obj, app->len);
}
ofono_sim_register(sim);
ofono_sim_inserted_notify(sim, TRUE);
return;
fail:
DBG("Decoding application list failed");
g_isi_client_destroy(sd->client);
sd->client = NULL;
ofono_sim_remove(sim);
}
static void uicc_status_resp(const GIsiMessage *msg, void *data)
{
struct ofono_sim *sim = data;
struct sim_data *sd = ofono_sim_get_data(sim);
const uint8_t req[] = {
UICC_APPLICATION_REQ,
UICC_APPL_LIST,
0, /* Number of subblocks */
};
if (!check_resp(msg, UICC_RESP, UICC_STATUS_GET))
goto fail;
DBG("");
if (g_isi_msg_error(msg) < 0)
goto fail;
if (g_isi_client_send(sd->client, req, sizeof(req), uicc_app_list_resp,
data, NULL))
return;
fail:
g_isi_client_destroy(sd->client);
sd->client = NULL;
ofono_sim_remove(sim);
}
static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_sim *sim = data;
struct sim_data *sd = ofono_sim_get_data(sim);
const uint8_t req[] = {
UICC_REQ, UICC_STATUS_GET,
};
ISI_RESOURCE_DBG(msg);
if (g_isi_msg_error(msg) < 0)
goto fail;
if (g_isi_client_send(sd->client, req, sizeof(req), uicc_status_resp,
data, NULL))
return;
fail:
g_isi_client_destroy(sd->client);
sd->client = NULL;
ofono_sim_remove(sim);
}
static int uicc_sim_probe(struct ofono_sim *sim, unsigned int vendor,
void *user)
{
GIsiModem *modem = user;
struct sim_data *sd;
sd = g_try_new0(struct sim_data, 1);
if (sd == NULL)
return -ENOMEM;
sd->client = g_isi_client_create(modem, PN_UICC);
if (sd->client == NULL) {
g_free(sd);
return -ENOMEM;
}
g_hash_table_insert(g_modems, g_isi_client_modem(sd->client), sim);
ofono_sim_set_data(sim, sd);
g_isi_client_ind_subscribe(sd->client, UICC_IND, uicc_ind_cb, sim);
g_isi_client_ind_subscribe(sd->client, UICC_CARD_IND, card_ind_cb,
sim);
g_isi_client_ind_subscribe(sd->client, UICC_CARD_READER_IND,
card_ind_cb, sim);
g_isi_client_ind_subscribe(sd->client, UICC_PIN_IND, pin_ind_cb, sim);
g_isi_client_ind_subscribe(sd->client, UICC_APPLICATION_IND,
app_ind_cb, sim);
g_isi_client_verify(sd->client, uicc_reachable_cb, sim, NULL);
return 0;
}
static void uicc_sim_remove(struct ofono_sim *sim)
{
struct sim_data *data = ofono_sim_get_data(sim);
ofono_sim_set_data(sim, NULL);
if (data == NULL)
return;
g_hash_table_remove(g_modems, g_isi_client_modem(data->client));
g_isi_client_destroy(data->client);
g_free(data);
}
static struct ofono_sim_driver driver = {
.name = "wgmodem2.5",
.probe = uicc_sim_probe,
.remove = uicc_sim_remove,
.read_file_info = uicc_read_file_info,
.read_file_transparent = uicc_read_file_transparent,
.read_file_linear = uicc_read_file_linear,
.read_file_cyclic = uicc_read_file_cyclic,
.write_file_transparent = uicc_write_file_transparent,
.write_file_linear = uicc_write_file_linear,
.write_file_cyclic = uicc_write_file_cyclic,
.read_imsi = uicc_read_imsi,
.query_passwd_state = uicc_query_passwd_state,
.send_passwd = uicc_send_passwd,
.query_pin_retries = uicc_query_pin_retries,
.reset_passwd = uicc_reset_passwd,
.change_passwd = uicc_change_passwd,
.lock = uicc_lock,
.query_locked = uicc_query_locked,
};
void isi_uicc_init(void)
{
g_modems = g_hash_table_new(g_direct_hash, g_direct_equal);
ofono_sim_driver_register(&driver);
}
void isi_uicc_exit(void)
{
g_hash_table_destroy(g_modems);
ofono_sim_driver_unregister(&driver);
}
gboolean isi_uicc_properties(GIsiModem *modem, int *app_id, int *app_type,
int *client_id)
{
struct ofono_sim *sim;
struct sim_data *sd;
sim = g_hash_table_lookup(g_modems, modem);
if (sim == NULL)
return FALSE;
sd = ofono_sim_get_data(sim);
if (sd == NULL)
return FALSE;
if (app_id != NULL)
*app_id = sd->app_id;
if (app_type != NULL)
*app_type = sd->app_type;
if (client_id != NULL)
*client_id = sd->client_id;
return TRUE;
}

View File

@ -26,7 +26,10 @@
extern "C" {
#endif
#include <glib/gtypes.h>
#include <gisi/client.h>
#include <gisi/modem.h>
#define PN_UICC 0x8C
@ -287,6 +290,9 @@ enum uicc_app_param {
UICC_APP_PARAM_URL = 0x5F50,
};
gboolean isi_uicc_properties(GIsiModem *modem, int *app_id, int *app_type,
int *client_id);
#ifdef __cplusplus
};
#endif