* [PATCH v2 00/18] wgmodem2.5 support
@ 2011-02-23 11:43 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
` (17 more replies)
0 siblings, 18 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2684 bytes --]
Hi,
Second go on the patches for wgmodem2.5, please review.
Note that we are still working on the changes for pipe/pep and CBS, having some
problems with testing them so those patches are not updated in this set just
included to ensure no conflicts.
Cheers
Andreas
Jessica Nilsson (18):
gisi: pipe and pep for wgmodem2.5
isimodem: added codepoints for u8500
plugins: add plugin for u8500
plugins: add u8500 to udev
gisi: add getter and setter for sim
src: add missing SIM enum to simutil.h
isimodem: code points uicc sim wgmodem2.5
isimodem: UICC sim support for wgmodem2.5
isimodem: clip colp clir colr wgmodem2.5
isimodem: wgmodem2.5 added to voicecall
isimodem: wgmodem2.5 support in USSD
isimodem: SS_GSM_BARRING_INFO added
isimodem: wgmodem2.5 added to call-forwarding
isimodem: wgmodem2.5 added to ssn
isimodem: code points for sms wgmodem2.5
isimodem: sms updated with wgmodem2.5
isimodem: CBS for wgmodem2.5
isimodem: initial support for UICC phonebook
Makefile.am | 7 +-
drivers/isimodem/call-barring.c | 99 ++-
drivers/isimodem/call-forwarding.c | 28 +-
drivers/isimodem/call-settings.c | 711 ++++++++++-
drivers/isimodem/call.h | 89 ++
drivers/isimodem/cbs.c | 414 +++++-
drivers/isimodem/debug.c | 149 ++
drivers/isimodem/debug.h | 2 +
drivers/isimodem/info.h | 3 +
drivers/isimodem/phonebook.c | 1273 +++++++++++++++++-
drivers/isimodem/sim.c | 2678 +++++++++++++++++++++++++++++++++---
drivers/isimodem/sms.c | 958 +++++++++++--
drivers/isimodem/sms.h | 41 +-
drivers/isimodem/ss.h | 22 +
drivers/isimodem/ssn.c | 406 ++++++-
drivers/isimodem/uicc.h | 265 ++++
drivers/isimodem/ussd.c | 36 +-
drivers/isimodem/voicecall.c | 218 +++-
gisi/message.c | 8 +
gisi/message.h | 1 +
gisi/modem.c | 42 +
gisi/modem.h | 4 +
gisi/pep.c | 330 +++++
gisi/pep.h | 6 +
gisi/pipe.c | 180 +++-
gisi/pipe.h | 17 +
plugins/ofono.rules | 3 +
plugins/u8500.c | 708 ++++++++++
plugins/udev.c | 2 +
src/simutil.h | 1 +
30 files changed, 8192 insertions(+), 509 deletions(-)
create mode 100644 drivers/isimodem/uicc.h
create mode 100644 plugins/u8500.c
--
1.7.3.5
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 01/18] gisi: pipe and pep for wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 11:43 ` [PATCH v2 02/18] isimodem: added codepoints for u8500 Andreas Westin
` (16 subsequent siblings)
17 siblings, 0 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 21077 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
gisi/message.c | 8 ++
gisi/message.h | 1 +
gisi/modem.c | 20 ++++
gisi/modem.h | 1 +
gisi/pep.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gisi/pep.h | 6 +
gisi/pipe.c | 180 ++++++++++++++++++++++++++++--
gisi/pipe.h | 17 +++
8 files changed, 551 insertions(+), 12 deletions(-)
diff --git a/gisi/message.c b/gisi/message.c
index 8f4fe5a..9d00108 100644
--- a/gisi/message.c
+++ b/gisi/message.c
@@ -65,6 +65,14 @@ uint8_t g_isi_msg_resource(const GIsiMessage *msg)
return msg->addr->spn_resource;
}
+uint8_t g_isi_msg_device(const GIsiMessage *msg)
+{
+ if (msg == NULL || msg->addr == NULL)
+ return 0;
+
+ return msg->addr->spn_dev;
+}
+
uint16_t g_isi_msg_object(const GIsiMessage *msg)
{
if (msg == NULL || msg->addr == NULL)
diff --git a/gisi/message.h b/gisi/message.h
index 95348f8..f34ce57 100644
--- a/gisi/message.h
+++ b/gisi/message.h
@@ -52,6 +52,7 @@ int g_isi_msg_version_minor(const GIsiMessage *msg);
int g_isi_msg_error(const GIsiMessage *msg);
const char *g_isi_msg_strerror(const GIsiMessage *msg);
uint8_t g_isi_msg_resource(const GIsiMessage *msg);
+uint8_t g_isi_msg_device(const GIsiMessage *msg);
uint16_t g_isi_msg_object(const GIsiMessage *msg);
uint8_t g_isi_msg_id(const GIsiMessage *msg);
diff --git a/gisi/modem.c b/gisi/modem.c
index f745bb2..7657bd1 100644
--- a/gisi/modem.c
+++ b/gisi/modem.c
@@ -519,6 +519,26 @@ GIsiModem *g_isi_modem_create_by_name(const char *name)
return g_isi_modem_create(if_nametoindex(name));
}
+guint g_isi_modem_add_to_watch(GIsiModem *modem, int fd)
+{
+ GIOChannel *channel;
+ guint watch;
+
+ if (modem == NULL || fd < 0)
+ return 0;
+
+ channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+ watch = g_io_add_watch(channel,
+ G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+ isi_callback, modem);
+ g_io_channel_unref(channel);
+
+ return watch;
+}
+
void *g_isi_modem_set_userdata(GIsiModem *modem, void *data)
{
void *old;
diff --git a/gisi/modem.h b/gisi/modem.h
index 0397a87..83ba92c 100644
--- a/gisi/modem.h
+++ b/gisi/modem.h
@@ -48,6 +48,7 @@ typedef void (*GIsiDebugFunc)(const char *fmt, ...);
GIsiModem *g_isi_modem_create(unsigned index);
GIsiModem *g_isi_modem_create_by_name(const char *name);
void g_isi_modem_destroy(GIsiModem *modem);
+guint g_isi_modem_add_to_watch(GIsiModem *modem, int fd);
unsigned g_isi_modem_index(GIsiModem *modem);
diff --git a/gisi/pep.c b/gisi/pep.c
index c82dc39..98b5ee0 100644
--- a/gisi/pep.c
+++ b/gisi/pep.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
@@ -30,10 +31,18 @@
#include <unistd.h>
#include <glib.h>
+#include "common.h"
#include "phonet.h"
#include "socket.h"
+#include "modem.h"
+#include "client.h"
+#include "server.h"
#include "pep.h"
+#define PN_PIPE 0xD9
+#define PN_PIPE_INVALID_HANDLE 0xFF
+#define PN_OBJ_PEP_GPRS 0x30
+
struct _GIsiPEP {
GIsiPEPCallback ready;
void *opaque;
@@ -42,6 +51,88 @@ struct _GIsiPEP {
uint16_t handle;
};
+struct isi_pipe_created_ind{
+ uint8_t cmd;
+ uint8_t pipe_handle;
+ uint8_t n_sb;
+ uint8_t sb_neg_fc;
+ uint8_t sb_len;
+ uint8_t tx_fc;
+ uint8_t rx_fc;
+};
+
+struct isi_pep_resp {
+ uint8_t pipe_handle;
+ uint8_t error_code;
+};
+
+struct isi_pep_connect_req{
+ uint8_t cmd;
+ uint8_t pipe_handle;
+ uint8_t state_after;
+ uint8_t other_pep_type;
+ uint8_t filler1;
+ uint8_t filler2;
+ uint8_t n_sb;
+ uint8_t data_sb;
+ uint8_t sb_len;
+ uint8_t alignment;
+ uint8_t filler;
+};
+
+struct isi_pipe_enabled_ind{
+ uint8_t cmd;
+ uint8_t pipe_handle;
+ uint8_t filler;
+};
+
+
+struct isi_pep_enable_req{
+ uint8_t cmd;
+ uint8_t pipe_handle;
+ uint8_t filler;
+};
+
+struct isi_pep_disconnect_req{
+ uint8_t cmd;
+ uint8_t pipe_handle;
+ uint8_t filler;
+};
+
+enum pn_flow_control {
+ PN_NO_FLOW_CONTROL = 0x00,
+ PN_LEGACY_FLOW_CONTROL = 0x01,
+ PN_ONE_CREDIT_FLOW_CONTROL = 0x02,
+ PN_MULTI_CREDIT_FLOW_CONTROL = 0x03,
+};
+
+enum isi_pep_message_id {
+ PNS_PEP_CONNECT_REQ = 0x40,
+ PNS_PEP_CONNECT_RESP = 0x41,
+ PNS_PEP_DISCONNECT_REQ = 0x42,
+ PNS_PEP_DISCONNECT_RESP = 0x43,
+ PNS_PEP_ENABLE_REQ = 0x46,
+ PNS_PEP_ENABLE_RESP = 0x47,
+ PNS_PIPE_CREATED_IND = 0x61,
+ PNS_PIPE_ENABLED_IND = 0x64,
+};
+
+enum isi_pep_sb_id {
+ PN_PIPE_SB_NEGOTIATED_FC = 0x03,
+ PN_PIPE_SB_ALIGNED_DATA = 0x06,
+};
+
+enum isi_pep_type {
+ PN_PEP_TYPE_COMMON
+};
+
+enum pn_pep_state { /* initial pep state */
+ PN_PEP_DISABLE,
+ PN_PEP_ENABLE,
+};
+
+
+static void g_isi_pep_disconnected(const GIsiMessage *msg, void *data);
static gboolean g_isi_pep_callback(GIOChannel *channel, GIOCondition cond,
gpointer data)
@@ -153,3 +244,242 @@ char *g_isi_pep_get_ifname(const GIsiPEP *pep, char *ifname)
return if_indextoname(g_isi_pep_get_ifindex(pep), ifname);
}
+
+static void g_isi_pep_connected(const GIsiMessage *msg, void *data)
+{
+ struct isi_pep_resp *resp;
+ size_t len = sizeof(struct isi_pep_resp);
+ GIsiPipe *pipe = data;
+ GIsiClient *client = g_isi_pipe_client(pipe);
+ struct isi_pipe_created_ind ind = {
+ .cmd = PNS_PIPE_CREATED_IND,
+ .pipe_handle = 0x00,
+ .n_sb = 0x01,
+ .sb_neg_fc = PN_PIPE_SB_NEGOTIATED_FC,
+ .sb_len = 0x04,
+ .tx_fc = PN_LEGACY_FLOW_CONTROL,
+ .rx_fc = PN_LEGACY_FLOW_CONTROL,
+ };
+
+ if (g_isi_msg_error(msg) < 0) {
+ g_isi_pipe_set_error_timeout(pipe);
+ return;
+ }
+
+ if (g_isi_msg_id(msg) != PNS_PEP_CONNECT_RESP)
+ return;
+
+ if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &resp, len))
+ return;
+
+ if (resp->pipe_handle == PN_PIPE_INVALID_HANDLE) {
+ g_isi_pipe_handle_error(pipe, resp->error_code);
+ return;
+ }
+
+ g_isi_pipe_set_handle(pipe, resp->pipe_handle);
+ ind.pipe_handle = resp->pipe_handle;
+
+ if (g_isi_request_sendto(g_isi_client_modem(client), msg->addr, &ind,
+ sizeof(ind), G_ISI_CLIENT_DEFAULT_TIMEOUT,
+ NULL, NULL, NULL) == NULL) {
+ g_isi_pipe_set_error_general(pipe);
+ return;
+ }
+
+ if (g_isi_msg_device(msg) == PN_DEV_HOST) {
+ g_isi_pep_connect(pipe, g_isi_pipe_get_handle(pipe),
+ PN_DEV_MODEM);
+ return;
+ }
+
+ if (g_isi_pipe_get_enabling(pipe))
+ g_isi_pipe_start(pipe);
+
+ g_isi_pipe_start_handler(pipe);
+
+}
+
+gboolean g_isi_pep_connect(GIsiPipe *pipe, uint8_t obj, uint8_t dev)
+{
+ GIsiClient *client = g_isi_pipe_client(pipe);
+ struct sockaddr_pn dst = {
+ .spn_family = AF_PHONET,
+ };
+ struct isi_pep_connect_req msg = {
+ .cmd = PNS_PEP_CONNECT_REQ,
+ .pipe_handle = obj,
+ .state_after = PN_PEP_DISABLE,
+ .other_pep_type = PN_PEP_TYPE_COMMON,
+ .filler1 = 0x00,
+ .filler2 = 0x00,
+ .n_sb = 0x00,
+ };
+
+ if (dev == PN_DEV_HOST) {
+ dst.spn_dev = PN_DEV_HOST;
+ dst.spn_resource = PN_PIPE;
+ dst.spn_obj = obj;
+ } else if (dev == PN_DEV_MODEM) {
+ dst.spn_dev = PN_DEV_MODEM;
+ dst.spn_resource = g_isi_client_resource(client);
+ dst.spn_obj = PN_OBJ_PEP_GPRS;
+ } else
+ return FALSE;
+
+ if (g_isi_request_sendto(g_isi_client_modem(client), &dst, &msg,
+ sizeof(msg), G_ISI_CLIENT_DEFAULT_TIMEOUT,
+ g_isi_pep_connected, pipe, NULL) == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void g_isi_pep_enabled(const GIsiMessage *msg, void *data)
+{
+ struct isi_pep_resp *resp;
+ size_t len = sizeof(struct isi_pep_resp);
+ GIsiPipe *pipe = data;
+ GIsiClient *client = g_isi_pipe_client(pipe);
+ struct isi_pipe_enabled_ind ind = {
+ .cmd = PNS_PIPE_ENABLED_IND,
+ .pipe_handle = g_isi_pipe_get_handle(pipe),
+ .filler = 0x00,
+ };
+
+ if (g_isi_msg_error(msg) < 0) {
+ g_isi_pipe_set_error_timeout(pipe);
+ return;
+ }
+
+ if (g_isi_msg_id(msg) != PNS_PEP_ENABLE_RESP)
+ return;
+
+ if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &resp, len))
+ return;
+
+ if (g_isi_pipe_get_handle(pipe) != resp->pipe_handle) {
+ g_isi_pipe_set_error_invalid_handle(pipe);
+ return;
+ }
+
+ g_isi_pipe_handle_error(pipe, resp->error_code);
+ if (g_isi_pipe_get_error(pipe))
+ return;
+
+ if (g_isi_request_sendto(g_isi_client_modem(client), msg->addr, &ind,
+ sizeof(ind), G_ISI_CLIENT_DEFAULT_TIMEOUT,
+ NULL, NULL, NULL) == NULL) {
+ g_isi_pipe_set_error_general(pipe);
+ return;
+ }
+
+ if (g_isi_msg_device(msg) == PN_DEV_MODEM) {
+ g_isi_pep_enable(pipe, PN_DEV_HOST);
+ return;
+ }
+ g_isi_pipe_set_enabling(pipe, FALSE);
+
+ if (!g_isi_pipe_get_error(pipe))
+ g_isi_pipe_set_enabled(pipe, TRUE);
+}
+
+void g_isi_pep_enable(GIsiPipe *pipe, uint8_t dev)
+{
+ GIsiClient *client = g_isi_pipe_client(pipe);
+ struct sockaddr_pn dst = {
+ .spn_family = AF_PHONET,
+ };
+ struct isi_pep_enable_req msg = {
+ .cmd = PNS_PEP_ENABLE_REQ,
+ .pipe_handle = g_isi_pipe_get_handle(pipe),
+ .filler = 0x00,
+ };
+
+ if (dev == PN_DEV_HOST) {
+ dst.spn_dev = PN_DEV_HOST;
+ dst.spn_resource = PN_PIPE;
+ dst.spn_obj = g_isi_pipe_get_handle(pipe);
+ } else if (dev == PN_DEV_MODEM) {
+ dst.spn_dev = PN_DEV_MODEM;
+ dst.spn_resource = g_isi_client_resource(client);
+ dst.spn_obj = PN_OBJ_PEP_GPRS;
+ } else
+ return;
+
+ if (g_isi_request_sendto(g_isi_client_modem(client), &dst, &msg,
+ sizeof(msg), G_ISI_CLIENT_DEFAULT_TIMEOUT,
+ g_isi_pep_enabled, pipe, NULL) == NULL)
+ return;
+
+ return;
+}
+
+static void g_isi_pep_disconnected(const GIsiMessage *msg, void *data)
+{
+ struct isi_pep_resp *resp;
+ size_t len = sizeof(struct isi_pep_resp);
+ GIsiPipe *pipe = data;
+
+ if (g_isi_msg_error(msg) < 0) {
+ g_isi_pipe_set_error_timeout(pipe);
+ return;
+ }
+
+ if (g_isi_msg_id(msg) != PNS_PEP_DISCONNECT_RESP)
+ return;
+
+ if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &resp, len))
+ return;
+
+ if (resp->pipe_handle == PN_PIPE_INVALID_HANDLE) {
+ g_isi_pipe_handle_error(pipe, resp->error_code);
+ return;
+ }
+
+ if (g_isi_pipe_get_handle(pipe) != resp->pipe_handle) {
+ g_isi_pipe_set_error_invalid_handle(pipe);
+ return;
+ }
+
+ if (g_isi_msg_device(msg) == PN_DEV_HOST) {
+ g_isi_pep_disconnect(pipe, PN_DEV_MODEM);
+ return;
+ }
+
+ g_isi_pipe_server_destroy(pipe);
+ g_isi_client_destroy(g_isi_pipe_client(pipe));
+ g_free(pipe);
+}
+
+
+void g_isi_pep_disconnect(GIsiPipe *pipe, uint8_t dev)
+{
+ GIsiClient *client = g_isi_pipe_client(pipe);
+ struct sockaddr_pn dst = {
+ .spn_family = AF_PHONET,
+ };
+ struct isi_pep_disconnect_req msg = {
+ .cmd = PNS_PEP_DISCONNECT_REQ,
+ .pipe_handle = g_isi_pipe_get_handle(pipe),
+ .filler = 0x00,
+ };
+
+ if (dev == PN_DEV_HOST) {
+ dst.spn_dev = PN_DEV_HOST;
+ dst.spn_resource = PN_PIPE;
+ dst.spn_obj = g_isi_pipe_get_handle(pipe);
+ } else if (dev == PN_DEV_MODEM) {
+ dst.spn_dev = PN_DEV_MODEM;
+ dst.spn_resource = g_isi_client_resource(client);
+ dst.spn_obj = PN_OBJ_PEP_GPRS;
+ } else
+ return;
+
+ if (g_isi_request_sendto(g_isi_client_modem(client), &dst, &msg,
+ sizeof(msg), G_ISI_CLIENT_DEFAULT_TIMEOUT,
+ g_isi_pep_disconnected, pipe, NULL) == NULL)
+ return;
+
+ return;
+}
diff --git a/gisi/pep.h b/gisi/pep.h
index d46c8d0..1be5e10 100644
--- a/gisi/pep.h
+++ b/gisi/pep.h
@@ -23,6 +23,7 @@
#define __GISI_PEP_H
#include "modem.h"
+#include "pipe.h"
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,11 @@ uint16_t g_isi_pep_get_object(const GIsiPEP *pep);
unsigned g_isi_pep_get_ifindex(const GIsiPEP *pep);
char *g_isi_pep_get_ifname(const GIsiPEP *pep, char *ifname);
+void g_isi_pep_enable(GIsiPipe *pipe, uint8_t dev);
+gboolean g_isi_pep_connect(GIsiPipe *pipe, uint8_t obj, uint8_t dev);
+void g_isi_pep_disconnect(GIsiPipe *pipe, uint8_t dev);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/gisi/pipe.c b/gisi/pipe.c
index 1bd5140..cf7d3c6 100644
--- a/gisi/pipe.c
+++ b/gisi/pipe.c
@@ -24,15 +24,23 @@
#endif
#include <stdint.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <fcntl.h>
+#include <unistd.h>
#include <errno.h>
#include <glib.h>
#include "client.h"
#include "pipe.h"
+#include "pep.h"
+#include "common.h"
#define PN_PIPE 0xD9
#define PN_PIPE_INVALID_HANDLE 0xFF
+#define PN_OBJ_PEP_GPRS 0x30
+
struct isi_pipe_create_req {
uint8_t cmd;
uint8_t state_after;
@@ -73,6 +81,8 @@ struct isi_pipe_resp {
uint8_t error2;
};
+
+
enum isi_pipe_message_id {
PNS_PIPE_CREATE_REQ,
PNS_PIPE_CREATE_RESP,
@@ -86,6 +96,8 @@ enum isi_pipe_message_id {
PNS_PIPE_REDIRECT_RESP,
PNS_PIPE_DISABLE_REQ,
PNS_PIPE_DISABLE_RESP,
+ PNS_PIPE_CREATED_IND = 0x61,
+ PNS_PIPE_ENABLED_IND = 0x64,
};
enum pn_pipe_error { /* error codes */
@@ -103,6 +115,7 @@ enum pn_pipe_error { /* error codes */
PN_PIPE_ERR_NOT_SUPPORTED,
};
+
enum pn_pipe_state { /* initial pipe state */
PN_PIPE_DISABLE,
PN_PIPE_ENABLE,
@@ -113,6 +126,14 @@ enum pn_msg_priority {
PN_MSG_PRIORITY_HIGH,
};
+
+
+struct _GIsiPipeServer {
+ int fd;
+ guint watch;
+};
+typedef struct _GIsiPipeServer GIsiPipeServer;
+
struct _GIsiPipe {
GIsiClient *client;
GIsiPipeHandler handler;
@@ -122,8 +143,11 @@ struct _GIsiPipe {
uint8_t handle;
gboolean enabled;
gboolean enabling;
+ GIsiPipeServer *server;
};
+
+
static int g_isi_pipe_error(enum pn_pipe_error code)
{
switch (code) {
@@ -155,7 +179,7 @@ static int g_isi_pipe_error(enum pn_pipe_error code)
return -EBADMSG;
}
-static void g_isi_pipe_handle_error(GIsiPipe *pipe, uint8_t code)
+void g_isi_pipe_handle_error(GIsiPipe *pipe, uint8_t code)
{
int err = g_isi_pipe_error(code);
@@ -168,6 +192,61 @@ static void g_isi_pipe_handle_error(GIsiPipe *pipe, uint8_t code)
pipe->error_handler(pipe);
}
+
+GIsiClient *g_isi_pipe_client(GIsiPipe *pipe)
+{
+ return pipe != NULL ? pipe->client : NULL;
+}
+
+
+void g_isi_pipe_set_handle(GIsiPipe *pipe, uint8_t handle)
+{
+ pipe->handle = handle;
+}
+
+static GIsiPipeServer *g_isi_pipe_server_create(GIsiModem *modem)
+{
+ GIsiPipeServer *server;
+ unsigned ifindex = g_isi_modem_index(modem);
+ struct sockaddr_pn addr = {
+ .spn_family = AF_PHONET,
+ .spn_resource = PN_PIPE,
+ .spn_obj = PN_OBJ_PEP_GPRS,
+ };
+ char buf[IF_NAMESIZE];
+ int fd = socket(PF_PHONET, SOCK_DGRAM, 0);
+
+ if (fd == -1)
+ return NULL;
+
+ server = g_try_new0(GIsiPipeServer, 1);
+ if (server == NULL)
+ goto error;
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ /* Use blocking mode on purpose. */
+
+ if (ifindex == 0)
+ g_warning("Unspecified modem interface index");
+ else if (if_indextoname(ifindex, buf) == NULL ||
+ setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, IF_NAMESIZE))
+ goto error;
+
+ if (bind(fd, (void *)&addr, sizeof(addr)))
+ goto error;
+
+ server->fd = fd;
+ server->watch = g_isi_modem_add_to_watch(modem, fd);
+ if (!server->watch)
+ goto error;
+
+ return server;
+
+error:
+ close(fd);
+ return NULL;
+}
+
static void g_isi_pipe_created(const GIsiMessage *msg, void *data)
{
struct isi_pipe_resp *resp;
@@ -226,6 +305,7 @@ GIsiPipe *g_isi_pipe_create(GIsiModem *modem, GIsiPipeHandler cb, uint16_t obj1,
};
size_t len = sizeof(msg);
GIsiPipe *pipe;
+ gboolean legacy = g_isi_modem_flags(modem);
pipe = g_try_new0(GIsiPipe, 1);
if (pipe == NULL) {
@@ -247,16 +327,34 @@ GIsiPipe *g_isi_pipe_create(GIsiModem *modem, GIsiPipeHandler cb, uint16_t obj1,
pipe->enabled = FALSE;
pipe->handle = PN_PIPE_INVALID_HANDLE;
- if (g_isi_client_send(pipe->client, &msg, len,
- g_isi_pipe_created, pipe, NULL))
- return pipe;
+ if (legacy) {
+ if (!g_isi_client_send(pipe->client, &msg, len,
+ g_isi_pipe_created, pipe, NULL))
+ goto error;
+
+ } else {
+ pipe->server = g_isi_pipe_server_create(modem);
+ if (pipe->server == NULL)
+ goto error;
+
+ if (!g_isi_pep_connect(pipe, obj1 & 0xFF, PN_DEV_HOST)) {
+ g_isi_pipe_server_destroy(pipe);
+ goto error;
+ }
+ }
+ return pipe;
+
+
+error:
g_isi_client_destroy(pipe->client);
g_free(pipe);
return NULL;
}
+
+
static void g_isi_pipe_enabled(const GIsiMessage *msg, void *data)
{
GIsiPipe *pipe = data;
@@ -287,14 +385,20 @@ static void g_isi_pipe_enabled(const GIsiMessage *msg, void *data)
static void g_isi_pipe_enable(GIsiPipe *pipe)
{
+ GIsiModem *modem = g_isi_client_modem(pipe->client);
+ gboolean legacy = g_isi_modem_flags(modem);
struct isi_pipe_enable_req msg = {
.cmd = PNS_PIPE_ENABLE_REQ,
.pipe_handle = pipe->handle,
};
size_t len = sizeof(msg);
- g_isi_client_send(pipe->client, &msg, len,
- g_isi_pipe_enabled, pipe, NULL);
+ if (legacy)
+ g_isi_client_send(pipe->client, &msg, len,
+ g_isi_pipe_enabled, pipe, NULL);
+ else
+ g_isi_pep_enable(pipe, PN_DEV_MODEM);
+
}
/**
@@ -339,8 +443,8 @@ static void g_isi_pipe_removed(const GIsiMessage *msg, void *data)
if (pipe->handle != resp->pipe_handle)
return;
- pipe->handle = PN_PIPE_INVALID_HANDLE;
- pipe->error = -EPIPE;
+ g_isi_client_destroy(pipe->client);
+ g_free(pipe);
}
@@ -356,17 +460,32 @@ static void g_isi_pipe_remove(GIsiPipe *pipe)
g_isi_pipe_removed, pipe, NULL);
}
+
/**
* Destroy a pipe. If it was connected, it is removed.
* @param pipe pipe as returned from g_isi_pipe_create()
*/
void g_isi_pipe_destroy(GIsiPipe *pipe)
{
- if (!pipe->error)
- g_isi_pipe_remove(pipe);
+ GIsiModem *modem = g_isi_client_modem(pipe->client);
+ gboolean legacy = g_isi_modem_flags(modem);
+
+ if (!pipe->error) {
+ if (legacy)
+ g_isi_pipe_remove(pipe);
+ else
+ g_isi_pep_disconnect(pipe, PN_DEV_HOST);
+ }
- g_isi_client_destroy(pipe->client);
- g_free(pipe);
+}
+
+
+void g_isi_pipe_server_destroy(GIsiPipe *pipe)
+{
+ if (pipe->server->watch > 0)
+ g_source_remove(pipe->server->watch);
+
+ g_free(pipe->server);
}
void g_isi_pipe_set_error_handler(GIsiPipe *pipe, GIsiPipeErrorHandler cb)
@@ -403,3 +522,40 @@ uint8_t g_isi_pipe_get_handle(GIsiPipe *pipe)
{
return pipe->handle;
}
+
+void g_isi_pipe_start_handler(GIsiPipe *pipe)
+{
+ if (pipe->handler)
+ pipe->handler(pipe);
+}
+
+gboolean g_isi_pipe_get_enabling(GIsiPipe *pipe)
+{
+ return pipe->enabling;
+}
+
+void g_isi_pipe_set_enabling(GIsiPipe *pipe, gboolean value)
+{
+ pipe->enabling = value;
+}
+
+void g_isi_pipe_set_enabled(GIsiPipe *pipe, gboolean value)
+{
+ pipe->enabled = value;
+}
+
+void g_isi_pipe_set_error_general(GIsiPipe *pipe)
+{
+ g_isi_pipe_handle_error(pipe, PN_PIPE_ERR_GENERAL);
+
+}
+
+void g_isi_pipe_set_error_timeout(GIsiPipe *pipe)
+{
+ g_isi_pipe_handle_error(pipe, PN_PIPE_ERR_TIMEOUT);
+}
+
+void g_isi_pipe_set_error_invalid_handle(GIsiPipe *pipe)
+{
+ g_isi_pipe_handle_error(pipe, PN_PIPE_ERR_INVALID_HANDLE);
+}
\ No newline at end of file
diff --git a/gisi/pipe.h b/gisi/pipe.h
index 01265a9..4570821 100644
--- a/gisi/pipe.h
+++ b/gisi/pipe.h
@@ -26,24 +26,41 @@
extern "C" {
#endif
+#include "client.h"
+
struct _GIsiPipe;
typedef struct _GIsiPipe GIsiPipe;
+
typedef void (*GIsiPipeHandler)(GIsiPipe *pipe);
typedef void (*GIsiPipeErrorHandler)(GIsiPipe *pipe);
GIsiPipe *g_isi_pipe_create(GIsiModem *modem, GIsiPipeHandler cb, uint16_t obj1,
uint16_t obj2, uint8_t type1, uint8_t type2);
void g_isi_pipe_destroy(GIsiPipe *pipe);
+void g_isi_pipe_server_destroy(GIsiPipe *pipe);
void g_isi_pipe_set_error_handler(GIsiPipe *pipe, GIsiPipeErrorHandler cb);
int g_isi_pipe_get_error(const GIsiPipe *pipe);
void *g_isi_pipe_set_userdata(GIsiPipe *pipe, void *data);
void *g_isi_pipe_get_userdata(GIsiPipe *pipe);
uint8_t g_isi_pipe_get_handle(GIsiPipe *pipe);
+gboolean g_isi_pipe_get_enabling(GIsiPipe *pipe);
+void g_isi_pipe_set_enabling(GIsiPipe *pipe, gboolean value);
+void g_isi_pipe_set_enabled(GIsiPipe *pipe, gboolean value);
int g_isi_pipe_start(GIsiPipe *pipe);
+GIsiClient *g_isi_pipe_client(GIsiPipe *pipe);
+void g_isi_pipe_set_handle(GIsiPipe *pipe, uint8_t handle);
+void g_isi_pipe_start_handler(GIsiPipe *pipe);
+
+void g_isi_pipe_handle_error(GIsiPipe *pipe, uint8_t code);
+void g_isi_pipe_set_error_general(GIsiPipe *pipe);
+void g_isi_pipe_set_error_timeout(GIsiPipe *pipe);
+void g_isi_pipe_set_error_invalid_handle(GIsiPipe *pipe);
+
+
#ifdef __cplusplus
}
#endif
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 02/18] isimodem: added codepoints for u8500
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
2011-02-23 11:43 ` [PATCH v2 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 13:17 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 03/18] plugins: add plugin " Andreas Westin
` (15 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1227 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/debug.c | 1 +
drivers/isimodem/info.h | 3 +++
2 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index c14acc2..10d0201 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -481,6 +481,7 @@ const char *info_message_id_name(enum info_message_id value)
const char *info_subblock_name(enum info_subblock value)
{
switch (value) {
+ _(INFO_SB_MODEMSW_VERSION);
_(INFO_SB_PRODUCT_INFO_NAME);
_(INFO_SB_PRODUCT_INFO_MANUFACTURER);
_(INFO_SB_SN_IMEI_PLAIN);
diff --git a/drivers/isimodem/info.h b/drivers/isimodem/info.h
index bdf1596..60425bf 100644
--- a/drivers/isimodem/info.h
+++ b/drivers/isimodem/info.h
@@ -27,6 +27,8 @@ extern "C" {
#endif
#define PN_PHONE_INFO 0x1B
+#define PN_MODEM_INFO 0xC5
+
#define PN_EPOC_INFO 98
#define INFO_TIMEOUT 5
@@ -50,6 +52,7 @@ enum info_message_id {
};
enum info_subblock {
+ INFO_SB_MODEMSW_VERSION = 0x00,
INFO_SB_PRODUCT_INFO_NAME = 0x01,
INFO_SB_PRODUCT_INFO_MANUFACTURER = 0x07,
INFO_SB_SN_IMEI_PLAIN = 0x41,
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 03/18] plugins: add plugin for u8500
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
2011-02-23 11:43 ` [PATCH v2 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 02/18] isimodem: added codepoints for u8500 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 13:26 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 04/18] plugins: add u8500 to udev Andreas Westin
` (14 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 18538 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
Makefile.am | 3 +
plugins/u8500.c | 708 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 711 insertions(+), 0 deletions(-)
create mode 100644 plugins/u8500.c
diff --git a/Makefile.am b/Makefile.am
index 7bd7f4f..aa4f3f9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -144,6 +144,9 @@ builtin_sources += plugins/isiusb.c
builtin_modules += n900
builtin_sources += plugins/n900.c plugins/nokia-gpio.h plugins/nokia-gpio.c
+
+builtin_modules += u8500
+builtin_sources += plugins/u8500.c
endif
if ATMODEM
diff --git a/plugins/u8500.c b/plugins/u8500.c
new file mode 100644
index 0000000..78e1a97
--- /dev/null
+++ b/plugins/u8500.c
@@ -0,0 +1,708 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 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
+ * 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
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <gisi/netlink.h>
+#include <gisi/modem.h>
+#include <gisi/client.h>
+#include <gisi/message.h>
+#include <gisi/iter.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/phonebook.h>
+#include <ofono/netreg.h>
+#include <ofono/voicecall.h>
+#include <ofono/sms.h>
+#include <ofono/cbs.h>
+#include <ofono/sim.h>
+#include <ofono/ussd.h>
+#include <ofono/ssn.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-settings.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-meter.h>
+#include <ofono/radio-settings.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+
+#include "drivers/isimodem/isimodem.h"
+#include "drivers/isimodem/isiutil.h"
+#include "drivers/isimodem/mtc.h"
+#include "drivers/isimodem/debug.h"
+
+struct isi_data {
+ char const *ifname;
+ GIsiModem *modem;
+ GIsiClient *client;
+ GIsiPhonetNetlink *link;
+ enum GIsiPhonetLinkState linkstate;
+ unsigned interval;
+ int reported;
+ ofono_bool_t online;
+ struct isi_cb_data *online_cbd;
+};
+
+struct devinfo_data {
+ GIsiClient *client;
+};
+
+static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
+{
+ 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",
+ mce_message_id_name(g_isi_msg_id(msg)));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void report_powered(struct ofono_modem *modem, struct isi_data *isi,
+ ofono_bool_t powered)
+{
+ if (powered == isi->reported)
+ return;
+
+ isi->reported = powered;
+ ofono_modem_set_powered(modem, powered);
+}
+
+static void report_online(struct isi_data *isi, ofono_bool_t online)
+{
+ struct isi_cb_data *cbd = isi->online_cbd;
+ ofono_modem_online_cb_t cb = cbd->cb;
+
+ isi->online_cbd = NULL;
+
+ if (isi->online == online)
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ else
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
+static void set_power_by_mce_state(struct ofono_modem *modem,
+ struct isi_data *isi, int mce_state)
+{
+ switch (mce_state) {
+ case MCE_POWER_OFF:
+ report_powered(modem, isi, FALSE);
+ break;
+ case MCE_NORMAL:
+ if (isi->online_cbd)
+ report_online(isi, mce_state == MCE_NORMAL);
+ default:
+ report_powered(modem, isi, TRUE);
+ }
+}
+
+static void mce_state_ind_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct isi_data *isi = ofono_modem_get_data(modem);
+ uint8_t state;
+ uint8_t action;
+
+ if (isi == NULL || g_isi_msg_id(msg) != MCE_MODEM_STATE_IND)
+ return;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
+ !g_isi_msg_data_get_byte(msg, 1, &action))
+ return;
+
+ switch (action) {
+ case MCE_START:
+ DBG("target modem state: %s (0x%02X)",
+ mce_modem_state_name(state), state);
+ break;
+
+ case MCE_READY:
+ DBG("current modem state: %s (0x%02X)",
+ mce_modem_state_name(state), state);
+ set_power_by_mce_state(modem, isi, state);
+ break;
+ default:
+ break;
+ }
+}
+
+static void mce_rf_state_ind_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct isi_data *isi = ofono_modem_get_data(modem);
+ uint8_t state;
+ uint8_t action;
+
+ if (isi == NULL || g_isi_msg_id(msg) != MCE_RF_STATE_IND)
+ return;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
+ !g_isi_msg_data_get_byte(msg, 1, &action))
+ return;
+
+ switch (action) {
+ case MCE_READY:
+ DBG("current rf state: %s (0x%02X)",
+ mce_rf_state_name(state), state);
+ if (isi->online_cbd)
+ report_online(isi, state);
+ break;
+ case MCE_START:
+ default:
+ break;
+ }
+}
+
+static void mce_query_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct isi_data *isi = ofono_modem_get_data(modem);
+ uint8_t current;
+ uint8_t target;
+
+ if (!check_response_status(msg, MCE_MODEM_STATE_QUERY_RESP))
+ return;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, ¤t) ||
+ !g_isi_msg_data_get_byte(msg, 1, &target))
+ return;
+
+ DBG("Modem state: current=%s (0x%02X) target=%s (0x%02X)",
+ mce_modem_state_name(current), current,
+ mce_modem_state_name(target), target);
+
+ if (current == target)
+ set_power_by_mce_state(modem, isi, current);
+}
+
+static gboolean bootstrap_current_state(gpointer user)
+{
+ struct ofono_modem *om = user;
+ struct isi_data *isi = ofono_modem_get_data(om);
+
+ const uint8_t req[] = {
+ MCE_MODEM_STATE_QUERY_REQ,
+ 0x00, 0x00 /* Filler */
+ };
+ size_t len = sizeof(req);
+
+ g_isi_client_send(isi->client, req, len, mce_query_cb, om, NULL);
+
+ return FALSE;
+}
+
+static void reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_modem *om = data;
+ struct isi_data *isi = ofono_modem_get_data(om);
+
+ if (!g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+
+ g_isi_client_ind_subscribe(isi->client, MCE_MODEM_STATE_IND,
+ mce_state_ind_cb, om);
+
+ g_isi_client_ind_subscribe(isi->client, MCE_RF_STATE_IND,
+ mce_rf_state_ind_cb, om);
+
+ /*
+ * FIXME: There is a theoretical race condition here:
+ * g_isi_client_ind_subscribe() adds the actual message
+ * sending for committing changes to subscriptions in idle
+ * loop, which may or may not preserve ordering. Thus, we
+ * might miss a state indication if the bootstrap request ends
+ * up being sent first.
+ */
+ g_idle_add(bootstrap_current_state, om);
+}
+
+static void phonet_status_cb(GIsiModem *modem, enum GIsiPhonetLinkState st,
+ char const *ifname, void *data)
+{
+ struct ofono_modem *om = data;
+ struct isi_data *isi = ofono_modem_get_data(om);
+
+ DBG("Link %s (%u) is %s", isi->ifname, g_isi_modem_index(isi->modem),
+ st == PN_LINK_REMOVED ? "removed" :
+ st == PN_LINK_DOWN ? "down" : "up");
+
+ isi->linkstate = st;
+
+ if (st == PN_LINK_UP)
+ g_isi_client_verify(isi->client, reachable_cb, om, NULL);
+ else if (st == PN_LINK_DOWN)
+ set_power_by_mce_state(om, isi, MCE_POWER_OFF);
+}
+
+static int u8500_probe(struct ofono_modem *modem)
+{
+ const char *ifname = ofono_modem_get_string(modem, "Interface");
+ unsigned address = ofono_modem_get_integer(modem, "Address");
+ GIsiModem *isimodem;
+ GIsiClient *client = NULL;
+ GIsiPhonetNetlink *link = NULL;
+ struct isi_data *isi = NULL;
+
+ if (ifname == NULL)
+ return -EINVAL;
+
+ DBG("(%p) with %s", modem, ifname);
+
+ isimodem = g_isi_modem_create_by_name(ifname);
+ if (isimodem == NULL) {
+ DBG("Interface=%s: %s", ifname, strerror(errno));
+ return -errno;
+ }
+
+ g_isi_modem_set_userdata(isimodem, modem);
+
+ if (getenv("OFONO_ISI_DEBUG"))
+ g_isi_modem_set_debug(isimodem, ofono_debug);
+
+ if (getenv("OFONO_ISI_TRACE"))
+ g_isi_modem_set_trace(isimodem, isi_trace);
+
+ if (g_isi_pn_netlink_by_modem(isimodem)) {
+ DBG("%s: %s", ifname, strerror(EBUSY));
+ errno = EBUSY;
+ goto error;
+ }
+
+ link = g_isi_pn_netlink_start(isimodem, phonet_status_cb, modem);
+ if (link == NULL) {
+ DBG("%s: %s", ifname, strerror(errno));
+ goto error;
+ }
+
+ if (address) {
+ int error = g_isi_pn_netlink_set_address(isimodem, address);
+ if (error && error != -EEXIST) {
+ DBG("g_isi_pn_netlink_set_address(): %s\n",
+ strerror(-error));
+ errno = -error;
+ goto error;
+ }
+ }
+
+ isi = g_try_new0(struct isi_data, 1);
+ if (isi == NULL) {
+ errno = ENOMEM;
+ goto error;
+ }
+
+ client = g_isi_client_create(isimodem, PN_MODEM_MCE);
+ if (!client)
+ goto error;
+
+ g_isi_modem_set_device(isimodem, PN_DEV_MODEM);
+
+ isi->modem = isimodem;
+ isi->ifname = ifname;
+ isi->link = link;
+ isi->reported = -1;
+ isi->client = client;
+
+ ofono_modem_set_data(modem, isi);
+ return 0;
+
+error:
+ g_isi_pn_netlink_stop(link);
+ g_isi_client_destroy(client);
+ g_isi_modem_destroy(isimodem);
+ g_free(isi);
+
+ return -errno;
+}
+
+static void u8500_remove(struct ofono_modem *modem)
+{
+ struct isi_data *isi = ofono_modem_get_data(modem);
+
+ ofono_modem_set_data(modem, NULL);
+
+ if (isi == NULL)
+ return;
+
+ g_isi_pn_netlink_stop(isi->link);
+ g_isi_client_destroy(isi->client);
+ g_isi_modem_destroy(isi->modem);
+ g_free(isi);
+}
+
+static void mce_state_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_modem *modem = cbd->user;
+ ofono_modem_online_cb_t cb = cbd->cb;
+
+ struct isi_data *isi = ofono_modem_get_data(modem);
+ uint8_t cause;
+
+ if (!check_response_status(msg, MCE_RF_STATE_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &cause))
+ goto error;
+
+ DBG("MCE cause: %s (0x%02X)", mce_status_info(cause), cause);
+
+ if (cause == MCE_OK) {
+ isi->online_cbd = cbd;
+ return;
+ }
+
+ if (cause == MCE_ALREADY_ACTIVE) {
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ g_free(cbd);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+}
+
+static void u8500_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t cb, void *data)
+{
+ struct isi_data *isi = ofono_modem_get_data(modem);
+ struct isi_cb_data *cbd = isi_cb_data_new(modem, cb, data);
+ const uint8_t req[] = {
+ MCE_RF_STATE_REQ,
+ online ? MCE_RF_ON : MCE_RF_OFF,
+ 0x00
+ };
+
+ DBG("(%p) with %s", modem, isi->ifname);
+
+ if (cbd == NULL || isi == NULL)
+ goto error;
+
+ if (g_isi_client_send_with_timeout(isi->client, req, sizeof(req),
+ MTC_STATE_REQ_TIMEOUT,
+ mce_state_cb, cbd, NULL)) {
+ isi->online = online;
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+}
+
+static void u8500_pre_sim(struct ofono_modem *modem)
+{
+ struct isi_data *isi = ofono_modem_get_data(modem);
+
+ DBG("(%p) with %s", modem, isi->ifname);
+
+ ofono_sim_create(modem, 0, "isimodem", isi->modem);
+ ofono_devinfo_create(modem, 0, "u8500", isi->modem);
+ ofono_voicecall_create(modem, 0, "isimodem", isi->modem);
+}
+
+static void u8500_post_sim(struct ofono_modem *modem)
+{
+ struct isi_data *isi = ofono_modem_get_data(modem);
+
+ DBG("(%p) with %s", modem, isi->ifname);
+
+ ofono_phonebook_create(modem, 0, "isimodem", isi->modem);
+ ofono_call_forwarding_create(modem, 0, "isimodem", isi->modem);
+ ofono_radio_settings_create(modem, 0, "isimodem", isi->modem);
+}
+
+static void u8500_post_online(struct ofono_modem *modem)
+{
+ struct isi_data *isi = ofono_modem_get_data(modem);
+
+ DBG("(%p) with %s", modem, isi->ifname);
+
+ ofono_netreg_create(modem, 0, "wgmodem2.5", isi->modem);
+ ofono_sms_create(modem, 0, "isimodem", isi->modem);
+ ofono_cbs_create(modem, 0, "isimodem", isi->modem);
+ ofono_ssn_create(modem, 0, "isimodem", isi->modem);
+ ofono_ussd_create(modem, 0, "isimodem", isi->modem);
+ ofono_call_settings_create(modem, 0, "isimodem", isi->modem);
+ ofono_call_barring_create(modem, 0, "isimodem", isi->modem);
+ ofono_call_meter_create(modem, 0, "isimodem", isi->modem);
+ ofono_gprs_create(modem, 0, "isimodem", isi->modem);
+}
+
+static int u8500_enable(struct ofono_modem *modem)
+{
+ return 0;
+}
+
+static int u8500_disable(struct ofono_modem *modem)
+{
+ return 0;
+}
+
+static void u8500_info_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_devinfo_query_cb_t cb = cbd->cb;
+ GIsiSubBlockIter iter;
+ uint8_t msgid;
+ uint8_t status;
+
+ msgid = g_isi_msg_id(msg);
+ if (msgid != INFO_SERIAL_NUMBER_READ_RESP)
+ goto error;
+
+ if (g_isi_msg_error(msg) < 0)
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &status))
+ goto error;
+
+ if (status != INFO_OK)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ uint8_t id = g_isi_sb_iter_get_id(&iter);
+ uint8_t chars;
+ char *info = NULL;
+
+ if (id != INFO_SB_PRODUCT_INFO_MANUFACTURER &&
+ id != INFO_SB_PRODUCT_INFO_NAME &&
+ id != INFO_SB_MCUSW_VERSION &&
+ id != INFO_SB_SN_IMEI_PLAIN &&
+ id != INFO_SB_MODEMSW_VERSION)
+ continue;
+
+ if (g_isi_sb_iter_get_len(&iter) < 5)
+ goto error;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &chars, 3))
+ goto error;
+
+ if (!g_isi_sb_iter_get_latin_tag(&iter, &info, chars, 4))
+ goto error;
+
+ CALLBACK_WITH_SUCCESS(cb, info, cbd->data);
+
+ g_free(info);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, "", cbd->data);
+}
+
+static void u8500_devinfo_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_devinfo *info = data;
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+
+ ofono_devinfo_register(info);
+}
+
+static void u8500_query_manufacturer(struct ofono_devinfo *info,
+ ofono_devinfo_query_cb_t cb,
+ void *data)
+{
+ CALLBACK_WITH_FAILURE(cb, "", data);
+}
+
+static void u8500_query_model(struct ofono_devinfo *info,
+ ofono_devinfo_query_cb_t cb,
+ void *data)
+{
+ CALLBACK_WITH_FAILURE(cb, "", data);
+}
+
+static void u8500_query_revision(struct ofono_devinfo *info,
+ ofono_devinfo_query_cb_t cb,
+ void *data)
+{
+ struct devinfo_data *dev = ofono_devinfo_get_data(info);
+ struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
+ const unsigned char msg[] = {
+ INFO_SERIAL_NUMBER_READ_REQ,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, /* M_INFO_MODEMSW */
+ 0x00, 0x00
+ };
+ DBG("");
+
+ if (cbd == NULL || dev == NULL)
+ goto error;
+
+ if (g_isi_client_send(dev->client, msg, sizeof(msg),
+ u8500_info_resp_cb, cbd, g_free))
+ return;
+
+
+error:
+ CALLBACK_WITH_FAILURE(cb, "", data);
+ g_free(cbd);
+}
+
+static void u8500_query_serial(struct ofono_devinfo *info,
+ ofono_devinfo_query_cb_t cb,
+ void *data)
+{
+ char imei[16]; /* IMEI 15 digits + 1 null*/
+ char numbers[] = "1234567890";
+ FILE *fp = fopen("/etc/imei", "r");
+ DBG("");
+
+ if (fp == NULL) {
+ DBG("failed to open /etc/imei file");
+ goto error;
+ }
+
+ if (fgets(imei, 16, fp)) {
+ DBG(" IMEI = %s", imei);
+ if (15 == strspn(imei, numbers))
+ CALLBACK_WITH_SUCCESS(cb, imei, data);
+ else {
+ CALLBACK_WITH_FAILURE(cb, "", data);
+ fclose(fp);
+ goto error;
+ }
+ }
+
+ fclose(fp);
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, "", data);
+}
+
+static int u8500_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
+ void *user)
+{
+ GIsiModem *idx = user;
+ struct devinfo_data *data = g_try_new0(struct devinfo_data, 1);
+
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->client = g_isi_client_create(idx, PN_MODEM_INFO);
+ if (data->client == NULL)
+ goto nomem;
+
+ ofono_devinfo_set_data(info, data);
+
+ g_isi_client_set_timeout(data->client, INFO_TIMEOUT);
+ g_isi_client_verify(data->client, u8500_devinfo_reachable_cb,
+ info, NULL);
+
+ return 0;
+
+nomem:
+ g_isi_client_destroy(data->client);
+
+ g_free(data);
+ return -ENOMEM;
+
+}
+
+static void u8500_devinfo_remove(struct ofono_devinfo *info)
+{
+ struct devinfo_data *data = ofono_devinfo_get_data(info);
+
+ ofono_devinfo_set_data(info, NULL);
+
+ if (data == NULL)
+ return;
+
+ g_isi_client_destroy(data->client);
+ g_free(data);
+}
+
+static struct ofono_modem_driver driver = {
+ .name = "u8500",
+ .probe = u8500_probe,
+ .remove = u8500_remove,
+ .set_online = u8500_online,
+ .pre_sim = u8500_pre_sim,
+ .post_sim = u8500_post_sim,
+ .post_online = u8500_post_online,
+ .enable = u8500_enable,
+ .disable = u8500_disable,
+};
+
+static struct ofono_devinfo_driver devinfo_driver = {
+ .name = "u8500",
+ .probe = u8500_devinfo_probe,
+ .remove = u8500_devinfo_remove,
+ .query_manufacturer = u8500_query_manufacturer,
+ .query_model = u8500_query_model,
+ .query_revision = u8500_query_revision,
+ .query_serial = u8500_query_serial
+};
+
+static int u8500_init(void)
+{
+ int err;
+
+ err = ofono_modem_driver_register(&driver);
+
+ if (err < 0)
+ return err;
+
+ ofono_devinfo_driver_register(&devinfo_driver);
+
+ return 0;
+}
+
+static void u8500_exit(void)
+{
+ ofono_devinfo_driver_unregister(&devinfo_driver);
+
+ ofono_modem_driver_unregister(&driver);
+}
+
+OFONO_PLUGIN_DEFINE(u8500, "Generic modem driver for isi",
+ VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+ u8500_init, u8500_exit)
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 04/18] plugins: add u8500 to udev
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (2 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 03/18] plugins: add plugin " Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-25 15:40 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 05/18] gisi: add getter and setter for sim Andreas Westin
` (13 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1123 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
plugins/ofono.rules | 3 +++
plugins/udev.c | 2 ++
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/plugins/ofono.rules b/plugins/ofono.rules
index 121825e..2e315a3 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -357,6 +357,9 @@ SUBSYSTEMS=="usb", ENV{OFONO_DRIVER}="isiusb", ENV{OFONO_ISI_ADDRESS}="16"
# Nokia N900 modem
SUBSYSTEMS=="hsi", ENV{OFONO_DRIVER}="n900", ENV{OFONO_ISI_ADDRESS}="108"
+# STE u8500
+KERNEL=="shrm0", ENV{OFONO_DRIVER}="u8500"
+
LABEL="ofono_isi_end"
SUBSYSTEM!="usb", GOTO="ofono_end"
diff --git a/plugins/udev.c b/plugins/udev.c
index 84478d7..b73150e 100644
--- a/plugins/udev.c
+++ b/plugins/udev.c
@@ -666,6 +666,8 @@ done:
add_nokia(modem, udev_device);
else if (g_strcmp0(driver, "isiusb") == 0)
add_isi(modem, udev_device);
+ else if (g_strcmp0(driver, "u8500") == 0)
+ add_isi(modem, udev_device);
else if (g_strcmp0(driver, "n900") == 0)
add_isi(modem, udev_device);
else if (g_strcmp0(driver, "gobi") == 0)
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 05/18] gisi: add getter and setter for sim
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (3 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 04/18] plugins: add u8500 to udev Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 11:43 ` [PATCH v2 06/18] src: add missing SIM enum to simutil.h Andreas Westin
` (12 subsequent siblings)
17 siblings, 0 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1515 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
gisi/modem.c | 22 ++++++++++++++++++++++
gisi/modem.h | 3 +++
2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/gisi/modem.c b/gisi/modem.c
index 7657bd1..2f5e2ae 100644
--- a/gisi/modem.c
+++ b/gisi/modem.c
@@ -70,6 +70,7 @@ struct _GIsiModem {
GIsiNotifyFunc trace;
void *opaque;
unsigned long flags;
+ void *sim;
};
struct _GIsiPending {
@@ -560,6 +561,27 @@ void *g_isi_modem_get_userdata(GIsiModem *modem)
return modem->opaque;
}
+void *g_isi_modem_set_sim(GIsiModem *modem, void *sim)
+{
+ void *old;
+
+ if (modem == NULL)
+ return NULL;
+
+ old = modem->sim;
+ modem->sim = sim;
+
+ return old;
+}
+
+void *g_isi_modem_get_sim(GIsiModem *modem)
+{
+ if (modem == NULL)
+ return NULL;
+
+ return modem->sim;
+}
+
unsigned long g_isi_modem_flags(GIsiModem *modem)
{
if (modem == NULL)
diff --git a/gisi/modem.h b/gisi/modem.h
index 83ba92c..b328bf1 100644
--- a/gisi/modem.h
+++ b/gisi/modem.h
@@ -61,6 +61,9 @@ void g_isi_modem_set_debug(GIsiModem *modem, GIsiDebugFunc debug);
void *g_isi_modem_set_userdata(GIsiModem *modem, void *data);
void *g_isi_modem_get_userdata(GIsiModem *modem);
+void *g_isi_modem_set_sim(GIsiModem *modem, void *sim);
+void *g_isi_modem_get_sim(GIsiModem *modem);
+
unsigned long g_isi_modem_flags(GIsiModem *modem);
void g_isi_modem_set_flags(GIsiModem *modem, unsigned long flags);
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 06/18] src: add missing SIM enum to simutil.h
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (4 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 05/18] gisi: add getter and setter for sim Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5 Andreas Westin
` (11 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 570 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
src/simutil.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/simutil.h b/src/simutil.h
index a5a683b..16b210b 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -34,6 +34,7 @@ enum sim_fileid {
SIM_DFPHONEBOOK_FILEID = 0x5F3A,
SIM_DFMULTIMEDIA_FILEID = 0x5F3B,
SIM_EFLI_FILEID = 0x6F05,
+ SIM_EFARR_FILEID = 0x6F06,
SIM_EFIMSI_FILEID = 0x6F07,
SIM_EF_CPHS_MWIS_FILEID = 0x6F11,
SIM_EF_CPHS_CFF_FILEID = 0x6F13,
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (5 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 06/18] src: add missing SIM enum to simutil.h Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
` (10 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 12031 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
Makefile.am | 4 +-
drivers/isimodem/debug.c | 84 +++++++++++++++
drivers/isimodem/debug.h | 1 +
drivers/isimodem/uicc.h | 265 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 353 insertions(+), 1 deletions(-)
create mode 100644 drivers/isimodem/uicc.h
diff --git a/Makefile.am b/Makefile.am
index aa4f3f9..f34f9ec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -137,7 +137,9 @@ builtin_sources += $(gisi_sources) \
drivers/isimodem/gprs.c \
drivers/isimodem/gprs-context.c \
drivers/isimodem/gpds.h \
- drivers/isimodem/audio-settings.c
+ drivers/isimodem/audio-settings.c \
+ drivers/isimodem/uicc.h
+
builtin_modules += isiusb
builtin_sources += plugins/isiusb.c
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index 10d0201..89e4573 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -214,6 +214,90 @@ const char *mce_rf_state_name(enum mce_rf_state value)
return "MCE_RF<UNKNOWN>";
}
+const char *uicc_status_name(uint8_t value)
+{
+ switch (value) {
+ /* Request performed successfully */
+ _(UICC_STATUS_OK);
+ /* Error in performing the command */
+ _(UICC_STATUS_FAIL);
+ /* Status is Unknown */
+ _(UICC_STATUS_UNKNOWN);
+ /* Server is not ready */
+ _(UICC_STATUS_NOT_READY);
+ /* Server start up is completed */
+ _(UICC_STATUS_START_UP_COMPLETED);
+ /* Server is shutting down */
+ _(UICC_STATUS_SHUTTING_DOWN);
+ /* Smart card is not ready */
+ _(UICC_STATUS_CARD_NOT_READY);
+ /* Smart card is ready */
+ _(UICC_STATUS_CARD_READY);
+ /* Smart card is disconnected */
+ _(UICC_STATUS_CARD_DISCONNECTED);
+ /* Smart card is not present */
+ _(UICC_STATUS_CARD_NOT_PRESENT);
+ /* Smart card has been rejected */
+ _(UICC_STATUS_CARD_REJECTED);
+ /* Application is active */
+ _(UICC_STATUS_APPL_ACTIVE);
+ /* Application is not active */
+ _(UICC_STATUS_APPL_NOT_ACTIVE);
+ /* PIN verification used */
+ _(UICC_STATUS_PIN_ENABLED);
+ /* PIN verification not used */
+ _(UICC_STATUS_PIN_DISABLED);
+ }
+ return "UICC_STATUS<UNKNOWN>";
+}
+
+const char *uicc_subblock_name(uint8_t value)
+{
+ switch (value) {
+ _(UICC_SB_SHUT_DOWN_CONFIG);
+ _(UICC_SB_CARD_STATUS);
+ _(UICC_SB_CARD_INFO);
+ _(UICC_SB_CARD_REJECT_CAUSE);
+ _(UICC_SB_CLIENT);
+ _(UICC_SB_APPL_DATA_OBJECT);
+ _(UICC_SB_APPLICATION);
+ _(UICC_SB_APPL_INFO);
+ _(UICC_SB_APPL_STATUS);
+ _(UICC_SB_FCP);
+ _(UICC_SB_FCI);
+ _(UICC_SB_CHV);
+ _(UICC_SB_PIN);
+ _(UICC_SB_PIN_REF);
+ _(UICC_SB_PUK);
+ _(UICC_SB_PIN_SUBST);
+ _(UICC_SB_PIN_INFO);
+ _(UICC_SB_APPL_PATH);
+ _(UICC_SB_SESSION);
+ _(UICC_SB_FILE_DATA);
+ _(UICC_SB_APDU);
+ _(UICC_SB_TRANSPARENT_READ);
+ _(UICC_SB_TRANSPARENT_UPDATE);
+ _(UICC_SB_TRANSPARENT);
+ _(UICC_SB_LINEAR_FIXED);
+ _(UICC_SB_CYCLIC);
+ _(UICC_SB_TERMINAL_PROFILE);
+ _(UICC_SB_TERMINAL_RESPONSE);
+ _(UICC_SB_ENVELOPE);
+ _(UICC_SB_POLLING_SET);
+ _(UICC_SB_REFRESH);
+ _(UICC_SB_AID);
+ _(UICC_SB_REFRESH_RESULT);
+ _(UICC_SB_APDU_ACTIONS);
+ _(UICC_SB_OBJECT_ID);
+ _(UICC_SB_STATUS_WORD);
+ _(UICC_SB_APDU_SAP_INFO);
+ _(UICC_SB_ACCESS_MODE);
+ _(UICC_SB_RESP_INFO);
+ _(UICC_SB_APDU_SAP_CONFIG);
+ }
+ return "UICC_<UNKNOWN>";
+}
+
const char *sms_isi_cause_name(enum sms_isi_cause value)
{
switch (value) {
diff --git a/drivers/isimodem/debug.h b/drivers/isimodem/debug.h
index b92b48f..db01f04 100644
--- a/drivers/isimodem/debug.h
+++ b/drivers/isimodem/debug.h
@@ -27,6 +27,7 @@
#include "ss.h"
#include "mtc.h"
#include "sms.h"
+#include "uicc.h"
#include "sim.h"
#include "info.h"
#include "call.h"
diff --git a/drivers/isimodem/uicc.h b/drivers/isimodem/uicc.h
new file mode 100644
index 0000000..2400767
--- /dev/null
+++ b/drivers/isimodem/uicc.h
@@ -0,0 +1,265 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * 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 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
+ *
+ */
+
+#ifndef __ISIMODEM25_UICC_H
+#define __ISIMODEM25_UICC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gisi/client.h>
+
+#define PN_UICC 0x8C
+
+#define UICC_APPL_ID_UNKNOWN 0x00
+#define UICC_SFI_NOT_PRESENT 0x00
+#define UICC_SESSION_ID_NOT_USED 0x00
+
+enum uicc_status {
+ UICC_STATUS_OK = 0x00,
+ UICC_STATUS_FAIL = 0x01,
+ UICC_STATUS_UNKNOWN = 0x02,
+ UICC_STATUS_NOT_READY = 0x10,
+ UICC_STATUS_START_UP_COMPLETED = 0x11,
+ UICC_STATUS_SHUTTING_DOWN = 0x12,
+ UICC_STATUS_CARD_NOT_READY = 0x20,
+ UICC_STATUS_CARD_READY = 0x21,
+ UICC_STATUS_CARD_DISCONNECTED = 0x22,
+ UICC_STATUS_CARD_NOT_PRESENT = 0x23,
+ UICC_STATUS_CARD_REJECTED = 0x24,
+ UICC_STATUS_APPL_ACTIVE = 0x30,
+ UICC_STATUS_APPL_NOT_ACTIVE = 0x31,
+ UICC_STATUS_PIN_ENABLED = 0x40,
+ UICC_STATUS_PIN_DISABLED = 0x41
+};
+
+enum uicc_subblock {
+ UICC_SB_SHUT_DOWN_CONFIG = 0x0023,
+ UICC_SB_CARD_STATUS = 0x0001,
+ UICC_SB_CARD_INFO = 0x0024,
+ UICC_SB_CARD_REJECT_CAUSE = 0x0025,
+ UICC_SB_CLIENT = 0x001F,
+ UICC_SB_APPL_DATA_OBJECT = 0x0002,
+ UICC_SB_APPLICATION = 0x0003,
+ UICC_SB_APPL_INFO = 0x0004,
+ UICC_SB_APPL_STATUS = 0x0005,
+ UICC_SB_FCP = 0x0007,
+ UICC_SB_FCI = 0x001C,
+ UICC_SB_CHV = 0x001B,
+ UICC_SB_PIN = 0x0008,
+ UICC_SB_PIN_REF = 0x0009,
+ UICC_SB_PUK = 0x000A,
+ UICC_SB_PIN_SUBST = 0x000B,
+ UICC_SB_PIN_INFO = 0x000C,
+ UICC_SB_APPL_PATH = 0x000D,
+ UICC_SB_SESSION = 0x000E,
+ UICC_SB_FILE_DATA = 0x000F,
+ UICC_SB_APDU = 0x0014,
+ UICC_SB_TRANSPARENT_READ = 0x0010,
+ UICC_SB_TRANSPARENT_UPDATE = 0x0011,
+ UICC_SB_TRANSPARENT = 0x0012,
+ UICC_SB_LINEAR_FIXED = 0x0013,
+ UICC_SB_CYCLIC = 0x0026,
+ UICC_SB_TERMINAL_PROFILE = 0x0015,
+ UICC_SB_TERMINAL_RESPONSE = 0x001D,
+ UICC_SB_ENVELOPE = 0x0021,
+ UICC_SB_POLLING_SET = 0x0016,
+ UICC_SB_REFRESH = 0x0017,
+ UICC_SB_AID = 0x0006,
+ UICC_SB_REFRESH_RESULT = 0x0018,
+ UICC_SB_APDU_ACTIONS = 0x0019,
+ UICC_SB_OBJECT_ID = 0x001A,
+ UICC_SB_STATUS_WORD = 0x0020,
+ UICC_SB_APDU_SAP_INFO = 0x0022,
+ UICC_SB_ACCESS_MODE = 0x0027,
+ UICC_SB_RESP_INFO = 0x0028,
+ UICC_SB_APDU_SAP_CONFIG = 0x0029
+
+};
+
+enum uicc_message_id {
+ UICC_REQ = 0x00,
+ UICC_RESP = 0x01,
+ UICC_IND = 0x02,
+ UICC_CARD_REQ = 0x03,
+ UICC_CARD_RESP = 0x04,
+ UICC_CARD_IND = 0x05,
+ UICC_APPLICATION_REQ = 0x06,
+ UICC_APPLICATION_RESP = 0x07,
+ UICC_APPLICATION_IND = 0x08,
+ UICC_PIN_REQ = 0x09,
+ UICC_PIN_RESP = 0x0A,
+ UICC_PIN_IND = 0x0B,
+ UICC_APPL_CMD_REQ = 0x0C,
+ UICC_APPL_CMD_RESP = 0x0D,
+ UICC_APPL_CMD_IND = 0x0E,
+ UICC_CONNECTOR_REQ = 0x0F,
+ UICC_CONNECTOR_RESP = 0x10,
+ UICC_CAT_REQ = 0x12,
+ UICC_CAT_RESP = 0x13,
+ UICC_CAT_IND = 0x14,
+ UICC_APDU_REQ = 0x15,
+ UICC_APDU_RESP = 0x16,
+ UICC_APDU_RESET_IND = 0x17,
+ UICC_REFRESH_REQ = 0x18,
+ UICC_REFRESH_RESP = 0x19,
+ UICC_REFRESH_IND = 0x1A,
+ UICC_SIMLOCK_REQ = 0x1B,
+ UICC_SIMLOCK_RESP = 0x1C,
+ UICC_APDU_SAP_REQ = 0x1E,
+ UICC_APDU_SAP_RESP = 0x1F,
+ UICC_APDU_SAP_IND = 0x20,
+ UICC_PWR_CTRL_REQ = 0x21,
+ UICC_PWR_CTRL_RESP = 0x22,
+ UICC_PWR_CTRL_IND = 0x23
+};
+
+enum uicc_service_type {
+ UICC_APPL_LIST = 0x01,
+ UICC_APPL_HOST_ACTIVATE = 0x03,
+ UICC_APPL_START_UP_COMPLETE = 0x05,
+ UICC_APPL_SHUT_DOWN_INITIATED = 0x06,
+ UICC_APPL_STATUS_GET = 0x07,
+ UICC_APPL_HOST_DEACTIVATE = 0x09,
+ UICC_PIN_VERIFY = 0x11,
+ UICC_PIN_UNBLOCK = 0x12,
+ UICC_PIN_DISABLE = 0x13,
+ UICC_PIN_ENABLE = 0x14,
+ UICC_PIN_CHANGE = 0x15,
+ UICC_PIN_SUBSTITUTE = 0x16,
+ UICC_PIN_INFO = 0x17,
+ UICC_PIN_PROMPT_VERIFY = 0x18,
+ UICC_APPL_READ_TRANSPARENT = 0x21,
+ UICC_APPL_UPDATE_TRANSPARENT = 0x22,
+ UICC_APPL_READ_LINEAR_FIXED = 0x23,
+ UICC_APPL_UPDATE_LINEAR_FIXED = 0x24,
+ UICC_APPL_FILE_INFO = 0x25,
+ UICC_APPL_APDU_SEND = 0x26,
+ UICC_APPL_CLEAR_CACHE = 0x27,
+ UICC_APPL_SESSION_START = 0x28,
+ UICC_APPL_SESSION_END = 0x29,
+ UICC_APPL_READ_CYCLIC = 0x2A,
+ UICC_APPL_UPDATE_CYCLIC = 0x2B,
+ UICC_CONNECT = 0x31,
+ UICC_DISCONNECT = 0x32,
+ UICC_RECONNECT = 0x33,
+ UICC_CAT_ENABLE = 0x41,
+ UICC_CAT_DISABLE = 0x42,
+ UICC_CAT_TERMINAL_PROFILE = 0x43,
+ UICC_CAT_TERMINAL_RESPONSE = 0x44,
+ UICC_CAT_ENVELOPE = 0x45,
+ UICC_CAT_POLLING_SET = 0x46,
+ UICC_CAT_REFRESH = 0x47,
+ UICC_CAT_POLL = 0x48,
+ UICC_APDU_SEND = 0x51,
+ UICC_APDU_ATR_GET = 0x52,
+ UICC_APDU_CONTROL = 0x53,
+ UICC_REFRESH_STATUS = 0x61,
+ UICC_APPL_TERMINATED = 0x71,
+ UICC_APPL_RECOVERED = 0x72,
+ UICC_APPL_ACTIVATED = 0x75,
+ UICC_PIN_VERIFY_NEEDED = 0x81,
+ UICC_PIN_UNBLOCK_NEEDED = 0x82,
+ UICC_PIN_PERMANENTLY_BLOCKED = 0x83,
+ UICC_PIN_VERIFIED = 0x84,
+ UICC_CAT_FETCHED_CMD = 0x91,
+ UICC_CAT_NOT_SUPPORTED = 0x92,
+ UICC_CAT_REG_FAILED = 0x93,
+ UICC_CAT_REG_OK = 0x94,
+ UICC_REFRESH_PERMISSION = 0xA1,
+ UICC_REFRESH_STARTING = 0xA2,
+ UICC_REFRESH_CANCELLED = 0xA3,
+ UICC_REFRESH_NOW = 0xA4,
+ UICC_START_UP_COMPLETE = 0xB0,
+ UICC_STATUS_GET = 0xB1,
+ UICC_READY = 0xB2,
+ UICC_READY_FOR_ACTIVATION = 0xB3,
+ UICC_INITIALIZED = 0xB4,
+ UICC_SHUTTING_DOWN = 0xB5,
+ UICC_SHUT_DOWN_CONFIG = 0xB6,
+ UICC_ERROR = 0xB7,
+ UICC_CARD_DISCONNECTED = 0xC0,
+ UICC_CARD_REMOVED = 0xC1,
+ UICC_CARD_NOT_PRESENT = 0xC2,
+ UICC_CARD_READY = 0xC4,
+ UICC_CARD_STATUS_GET = 0xC5,
+ UICC_CARD_REJECTED = 0xC8,
+ UICC_CARD_INFO_GET = 0xC9,
+ UICC_SIMLOCK_ACTIVE = 0xD0,
+ UICC_APDU_SAP_ACTIVATE = 0xE1,
+ UICC_APDU_SAP_DEACTIVATE = 0xE2,
+ UICC_APDU_SAP_ATR_GET = 0xE3,
+ UICC_APDU_SAP_COLD_RESET = 0xE4,
+ UICC_APDU_SAP_WARM_RESET = 0xE5,
+ UICC_APDU_SAP_APDU_SEND = 0xE6,
+ UICC_APDU_SAP_RECOVERY = 0xE7,
+ UICC_APDU_SAP_CONFIG_GET = 0xE8,
+ UICC_PWR_CTRL_ENABLE = 0xF1,
+ UICC_PWR_CTRL_DISABLE = 0xF2,
+ UICC_PWR_CTRL_WAIT = 0xF3,
+ UICC_PWR_CTRL_PROCEED = 0xF4,
+ UICC_PWR_CTRL_PERMISSION = 0xFA
+};
+
+enum uicc_appl_type_table {
+ UICC_APPL_TYPE_UNKNOWN = 0x00,
+ UICC_APPL_TYPE_ICC_SIM = 0x01,
+ UICC_APPL_TYPE_UICC_USIM = 0x02
+};
+enum uicc_pin_qualifier {
+ UICC_PIN_NEW = 0x01,
+ UICC_PIN_OLD = 0x02
+};
+enum uicc_appl_start_up_type {
+ UICC_APPL_START_UP_NO_INIT_PROC = 0x00,
+ UICC_APPL_START_UP_INIT_PROC = 0x01
+};
+enum uicc_card_type {
+ UICC_CARD_TYPE_ICC = 0x01,
+ UICC_CARD_TYPE_UICC = 0x02
+};
+enum uicc_details {
+ UICC_NO_DETAILS = 0x00,
+ UICC_INVALID_PARAMETERS = 0x01,
+ UICC_FILE_NOT_FOUND = 0x02
+};
+enum uicc_simlock_status {
+ UICC_SIMLOCK_STATUS_ACTIVE = 0x01,
+ UICC_SIMLOCK_STATUS_INACTIVE = 0x02
+};
+
+enum uicc_apdu_status_words {
+ UICC_PIN_STATUS_AUTH_RETRIES = 0x63c0,
+ UICC_PIN_STATUS_AUTH_BLOCKED = 0x6983,
+ UICC_PIN_STATUS_AUTH_FAILED = 0x9840
+};
+
+int get_app_id(GIsiModem *modem);
+int get_app_type(GIsiModem *modem);
+int get_client_id(GIsiModem *modem);
+struct ofono_sim_driver *get_sim_driver_func(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_UICC_H */
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (6 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-25 15:20 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
` (9 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 74955 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/sim.c | 2678 ++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 2480 insertions(+), 198 deletions(-)
diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
index bfecbc9..117129b 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,22 +34,211 @@
#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
+
+#define ADF_USIM 0x7FFF
+#define MAX_SIM_APPS 0x08
+#define NOT_AVAILABLE -1
+#define NOT_ACTIVATED -1
+
+/* File info parameters */
+enum file_info_params {
+ FCP_TEMPLATE = 0x62,
+ FCP_FILE_SIZE = 0x80,
+ FCP_FILE_DESC = 0x82,
+ FCP_FILE_ID = 0x83,
+ FCP_FILE_LIFECYCLE = 0x8A,
+ FCP_FILE_SECURITY_ARR = 0x8B,
+ FCP_FILE_SECURITY_COMPACT = 0x8C,
+ FCP_FILE_SECURITY_EXPANDED = 0xAB,
+ FCP_PIN_STATUS = 0xC6,
+};
+
+struct sim_applications {
+ int app_list[MAX_SIM_APPS];
+ int app_type[MAX_SIM_APPS];
+};
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 sim_applications *sim_application_list_p;
+};
+
+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 {
+ int8_t passwd_type;
+ int8_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}
+};
+
+const uint8_t upin_id = 0x11;
+
+struct file_info {
+ int fileid;
+ int length;
+ int structure;
+ int record_length;
+ uint8_t access[3];
+ uint8_t file_status;
+};
+
+struct read_file_data {
+ struct file_info *info;
+ struct sim_data *sim_data;
+};
+
+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 }
+ },
};
struct sim_imsi {
@@ -66,14 +256,275 @@ 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 uint8_t fileid_to_short_fileid(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;
+}
+
+static int sim_applications_get_next_index(struct sim_applications *sa,
+ int current_app)
+{
+ int i;
+
+ if (current_app >= (MAX_SIM_APPS - 1))
+ return NOT_AVAILABLE;
+
+ for (i = ++current_app; i < MAX_SIM_APPS; i++) {
+
+ if (sa->app_list[i] && (sa->app_type[i] !=
+ UICC_APPL_TYPE_UNKNOWN))
+ return i;
+ }
+
+ return NOT_AVAILABLE;
+}
+
+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;
+}
+
+int get_app_id(GIsiModem *modem)
+{
+ struct ofono_sim *sim;
+
+ if (modem == NULL)
+ return -1;
+
+ sim = g_isi_modem_get_sim(modem);
+
+ if (sim) {
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ return sd->app_id;
+ } else
+ return -1;
+}
+
+int get_app_type(GIsiModem *modem)
+{
+ struct ofono_sim *sim;
+
+ if (modem == NULL)
+ return -1;
+
+ sim = g_isi_modem_get_sim(modem);
+
+ if (sim) {
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ return sd->app_type;
+ } else
+ return -1;
+}
+
+int get_client_id(GIsiModem *modem)
+{
+ struct ofono_sim *sim;
+
+ if (modem == NULL)
+ return -1;
+
+ sim = g_isi_modem_get_sim(modem);
+
+ if (sim) {
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ return sd->client_id;
+ } else
+ return -1;
+}
/* Returns file info */
static gboolean fake_file_info(gpointer user)
@@ -89,6 +540,286 @@ static gboolean fake_file_info(gpointer user)
return FALSE;
}
+static gboolean check_response_status_with_cause(const GIsiMessage *msg,
+ uint8_t msgid,
+ uint8_t service,
+ int cause,
+ int pos)
+{
+ uint8_t type;
+ uint8_t msg_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, &msg_cause) ||
+ msg_cause != 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;
+}
+
+static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
+ uint8_t service)
+{
+ int cause, pos;
+
+ if (g_isi_msg_version_major(msg) == 6 &&
+ g_isi_msg_version_minor(msg) >= 0) {
+ cause = UICC_STATUS_OK;
+ pos = 0;
+ } else {
+ cause = SIM_SERV_OK;
+ pos = 1;
+ }
+
+ return check_response_status_with_cause(msg, msgid, service, cause,
+ pos);
+}
+
+
+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;
+
+
+ if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
+ return;
+
+ if (fcp != FCP_TEMPLATE)
+ return;
+
+ if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
+ return;
+
+ while (read < fcp_len) {
+ if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
+ return;
+ if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
+ return;
+
+ 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 read_file_data *fdata = cbd->user;
+ struct file_info const *info;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd = NULL;
+ uint8_t sbcount = 0;
+
+ if (fdata != NULL) {
+ sd = fdata->sim_data;
+ info = fdata->info;
+ g_free(cbd->user);
+ cbd->user = NULL;
+ }
+
+ if (sd == NULL)
+ goto error;
+
+ 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)
{
@@ -98,276 +829,1700 @@ static void isi_read_file_info(struct ofono_sim *sim, int fileid,
{ 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;
- 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);
+ 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;
+ struct read_file_data *fdata = g_try_malloc0(sizeof(
+ struct read_file_data));
+
+ 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);
+
+ fdata->sim_data = sd;
+
+ for (i = 0; i < N; i++) {
+ if (fileid == static_file_info[i].fileid &&
+ cbd != NULL) {
+ fdata->info = (struct file_info *)
+ &static_file_info[i];
+ continue;
+ }
+ }
+ cbd->user = (void *) fdata;
+
+ 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,
+ /* Elementary file short id*/
+ fileid_to_short_fileid(fileid),
+ 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 gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
- uint8_t service)
+static void spn_resp_cb(const GIsiMessage *msg, void *data)
{
- uint8_t type;
- uint8_t cause;
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
- if (g_isi_msg_error(msg) < 0) {
- DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
- return FALSE;
- }
+ const struct sim_spn *resp = NULL;
+ size_t len = sizeof(struct sim_spn);
- if (g_isi_msg_id(msg) != msgid) {
- DBG("Unexpected msg: %s",
- sim_message_id_name(g_isi_msg_id(msg)));
- return FALSE;
- }
+ uint8_t spn[SIM_MAX_SPN_LENGTH + 1];
+ int i;
- 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 (!check_response_status(msg, SIM_SERV_PROV_NAME_RESP,
+ SIM_ST_READ_SERV_PROV_NAME))
+ goto error;
- if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
- DBG("Unexpected service: 0x%02X", type);
- return FALSE;
+ if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
+ goto error;
+
+ /* Set display condition bits */
+ spn[0] = (resp->disp_home & 0x01) | ((resp->disp_roam & 0x01) << 1);
+
+ /* Convert from a NULL-terminated UCS-2 string to ASCII */
+ for (i = 0; i < SIM_MAX_SPN_LENGTH; i++) {
+ uint16_t c = resp->name[i] >> 8 | resp->name[i] << 8;
+
+ if (c == 0)
+ c = 0xFF;
+ else if (!g_ascii_isprint(c))
+ c = '?';
+
+ spn[i + 1] = c;
}
- return TRUE;
+
+ CALLBACK_WITH_SUCCESS(cb, spn, sizeof(spn), cbd->data);
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
}
-static void spn_resp_cb(const GIsiMessage *msg, void *data)
+static gboolean isi_read_spn(struct ofono_sim *sim, struct isi_cb_data *cbd)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ const uint8_t msg[] = {
+ SIM_SERV_PROV_NAME_REQ,
+ SIM_ST_READ_SERV_PROV_NAME,
+ 0
+ };
+
+ if (sd == NULL)
+ return FALSE;
+
+ return g_isi_client_send(sd->client, msg, sizeof(msg),
+ spn_resp_cb, cbd, g_free);
+}
+
+static void read_iccid_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
+ struct sim_iccid *icc;
+ size_t len = sizeof(struct sim_iccid);
+
+ if (!check_response_status(msg, SIM_READ_FIELD_RESP, ICC))
+ goto error;
+
+ if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &icc, len))
+ goto error;
+
+ CALLBACK_WITH_SUCCESS(cb, icc->id, 10, cbd->data);
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
+static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ const uint8_t req[] = {
+ SIM_READ_FIELD_REQ,
+ ICC,
+ };
+
+ if (sd == NULL)
+ return FALSE;
+
+ return g_isi_client_send(sd->client, req, sizeof(req),
+ 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 || sd == NULL)
+ goto error;
+
+ 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,
+ /*Elementary file short id*/
+ fileid_to_short_fileid(fileid),
+ 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;
+
+ } else {
+ switch (fileid) {
+ case SIM_EFSPN_FILEID:
+ done = isi_read_spn(sim, cbd);
+ break;
+
+ case SIM_EF_ICCID_FILEID:
+ done = isi_read_iccid(sim, cbd);
+ break;
+
+ default:
+ done = FALSE;
+ }
+
+ if (done)
+ return;
+ }
+
+ DBG("Fileid %04X not implemented", fileid);
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+ g_free(cbd);
+}
+
+static void isi_read_file_linear_fixed_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_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,
+ /* Elementary file short file id*/
+ fileid_to_short_fileid(fileid),
+ 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,
+ int record, int length,
+ ofono_sim_read_cb_t cb, void *data)
+{
+ DBG("Fileid %04X not implemented", fileid);
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+}
+
+static void isi_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("Fileid %04X not implemented", 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,
+ fileid_to_short_fileid(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,
+ int length, const unsigned char *value,
+ ofono_sim_write_cb_t cb, void *data)
+{
+ DBG("Fileid %04X not implemented", fileid);
+ CALLBACK_WITH_FAILURE(cb, 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 = 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;
+ size_t len = sizeof(struct sim_imsi);
+
+ char imsi[SIM_MAX_IMSI_LENGTH + 1];
+ size_t i, j;
+
+ if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
+ goto error;
+
+ /* Ignore the low-order semi-octet of the first byte */
+ imsi[0] = ((resp->imsi[0] & 0xF0) >> 4) + '0';
+
+ for (i = 1, j = 1; i < resp->length && j < SIM_MAX_IMSI_LENGTH; i++) {
+ char nibble;
+
+ imsi[j++] = (resp->imsi[i] & 0x0F) + '0';
+ nibble = (resp->imsi[i] & 0xF0) >> 4;
+ if (nibble != 0x0F)
+ imsi[j++] = nibble + '0';
+ }
+
+ imsi[j] = '\0';
+ CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static void isi_read_imsi(struct ofono_sim *sim,
+ ofono_sim_imsi_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);
+ size_t len;
+
+ const uint8_t msg[] = {
+ SIM_IMSI_REQ_READ_IMSI,
+ READ_IMSI
+ };
+
+ 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;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, data);
+ g_free(cbd);
+}
+
+static void uicc_application_activate_req(GIsiClient *client,
+ void *opaque,
+ unsigned char appl_type,
+ unsigned char aid);
+
+
+static void uicc_application_activate_resp(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+ uint8_t status;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ if (g_isi_msg_id(msg) != UICC_APPLICATION_RESP)
+ return;
+
+ g_isi_msg_data_get_byte(msg, 1, &status);
+
+ if (status == UICC_STATUS_OK || status == 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(sd->sim_application_list_p);
+ }
+ } else {
+ int i = sim_applications_get_next_index(
+ sd->sim_application_list_p,
+ sd->trying_app_id);
+
+ if (i == NOT_AVAILABLE) {
+ g_free(sd->sim_application_list_p);
+ return;
+ }
+
+ DBG("Activation Error, trying to activate APP with ID:%d", i);
+ uicc_application_activate_req(sd->client, sim,
+ sd->sim_application_list_p->app_type[i],
+ sd->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;
+ }
+
+ sd->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);
+
+ sd->sim_application_list_p->app_list[appl_id] =
+ appl_id;
+ sd->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(
+ sd->sim_application_list_p,
+ NOT_ACTIVATED);
+
+ if (index != NOT_AVAILABLE) {
+ DBG("Activating APP index:%d", index);
+ sd->trying_app_id =
+ sd->sim_application_list_p->app_list[index];
+ sd->trying_app_type =
+ sd->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,
+ sd->sim_application_list_p->app_type[index],
+ sd->sim_application_list_p->app_list[index]);
+ } else
+ g_free(sd->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;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+ uint8_t sbcount = 0;
+
+ if (g_isi_msg_error(msg) < 0)
+ goto error;
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_VERIFY)) {
+ sd->passwd_required = FALSE;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ goto out;
+ }
+
+ 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 UICC_PIN_STATUS_AUTH_BLOCKED:
+ case UICC_PIN_STATUS_AUTH_FAILED:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) ==
+ UICC_PIN_STATUS_AUTH_RETRIES)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+ g_free(cbd);
+}
+
+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);
+ char pin[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
+
+ 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 */
+ };
+ struct iovec iov[2] = {
+ { msg, sizeof(msg) },
+ { pin, 8 }
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+
+ memmove(pin, passwd, pinlen);
+
+ g_isi_client_vsend_with_timeout(sd->client, iov, 2,
+ SIM_TIMEOUT, uicc_pin_enter_resp, cbd,
+ g_free);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+}
+
+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_pin_prompt_resp(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
- ofono_sim_read_cb_t cb = cbd->cb;
+ 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)) {
+
+ if (!check_response_status_with_cause(msg, UICC_PIN_RESP,
+ UICC_PIN_PROMPT_VERIFY,
+ UICC_STATUS_PIN_DISABLED, 1))
+ goto error;
+ }
- const struct sim_spn *resp = NULL;
- size_t len = sizeof(struct sim_spn);
+ g_isi_msg_data_get_byte(msg, 1, &status);
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ sd->pin_state_received = TRUE;
+ } 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);
+ }
+ }
- uint8_t spn[SIM_MAX_SPN_LENGTH + 1];
- int i;
+ 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);
+ }
- if (!check_response_status(msg, SIM_SERV_PROV_NAME_RESP,
- SIM_ST_READ_SERV_PROV_NAME))
- goto error;
+ 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 (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
- goto error;
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ uicc_pin_prompt(cbd->user,
+ OFONO_SIM_PASSWORD_SIM_PIN,
+ cb,
+ cbd->data,
+ UICC_PIN_INFO);
+ }
- /* Set display condition bits */
- spn[0] = (resp->disp_home & 0x01) | ((resp->disp_roam & 0x01) << 1);
+ CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
+ return;
+error:
+ DBG("PIN prompt verify failed");
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
- /* Convert from a NULL-terminated UCS-2 string to ASCII */
- for (i = 0; i < SIM_MAX_SPN_LENGTH; i++) {
- uint16_t c = resp->name[i] >> 8 | resp->name[i] << 8;
+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;
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ 0, /*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,
+ 0, /*PIN ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0 /*Filler*/
+ };
- if (c == 0)
- c = 0xFF;
- else if (!g_ascii_isprint(c))
- c = '?';
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
- spn[i + 1] = c;
+ if (cbd == NULL || sd == NULL) {
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ g_free(cbd);
+ return;
}
- CALLBACK_WITH_SUCCESS(cb, spn, sizeof(spn), cbd->data);
- return;
+ if (sd->current_pin_id == 0) {
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ g_free(cbd);
+ return;
+ }
-error:
- CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+ msg[2] = sd->app_id;
+ msg[11] = sd->current_pin_id;
+
+ g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SIM_TIMEOUT, uicc_pin_prompt_resp,
+ cbd, g_free);
}
-static gboolean isi_read_spn(struct ofono_sim *sim, struct isi_cb_data *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;
- const uint8_t msg[] = {
- SIM_SERV_PROV_NAME_REQ,
- SIM_ST_READ_SERV_PROV_NAME,
- 0
- };
+ if (sd->pin_state_received) {
+ int lock_type = OFONO_SIM_PASSWORD_NONE;
- if (sd == NULL)
- return FALSE;
+ 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;
- return g_isi_client_send(sd->client, msg, sizeof(msg),
- spn_resp_cb, cbd, g_free);
+ 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, OFONO_SIM_PASSWORD_SIM_PIN,
+ cb, data, UICC_PIN_PROMPT_VERIFY);
+ return;
+ }
+
+ DBG("No UICC_PIN_IND received");
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ }
}
-static void read_iccid_resp_cb(const GIsiMessage *msg, void *data)
+static void uicc_pin_enable_resp(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
- ofono_sim_read_cb_t cb = cbd->cb;
- struct sim_iccid *icc;
- size_t len = sizeof(struct sim_iccid);
+ 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);
- if (!check_response_status(msg, SIM_READ_FIELD_RESP, ICC))
- goto error;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
- if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &icc, len))
+ if (g_isi_msg_error(msg) < 0)
goto error;
- CALLBACK_WITH_SUCCESS(cb, icc->id, 10, cbd->data);
- return;
-
-error:
- CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
-}
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_DISABLE) &&
+ !check_response_status(msg, UICC_PIN_RESP,
+ UICC_PIN_ENABLE))
+ goto cont;
-static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
-{
- struct sim_data *sd = ofono_sim_get_data(sim);
+ DBG("PIN lock/unlock succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
- const uint8_t req[] = {
- SIM_READ_FIELD_REQ,
- ICC,
- };
+cont:
+ 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 UICC_PIN_STATUS_AUTH_BLOCKED:
+ case UICC_PIN_STATUS_AUTH_FAILED:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) ==
+ UICC_PIN_STATUS_AUTH_RETRIES)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+ }
+ default:
+ break;
+ }
- if (sd == NULL)
- return FALSE;
+ g_isi_sb_iter_next(&iter);
+ }
- return g_isi_client_send(sd->client, req, sizeof(req),
- read_iccid_resp_cb, cbd, g_free);
+error:
+ DBG("PIN lock/unlock failed");
+ CALLBACK_WITH_FAILURE(cb, 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)
+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 isi_cb_data *cbd;
- gboolean done;
+ 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;
- 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;
-
- case SIM_EF_ICCID_FILEID:
- done = isi_read_iccid(sim, cbd);
- break;
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
- default:
- done = FALSE;
- }
+ if (sd->current_pin_id == 0)
+ goto error;
- if (done)
+ if (enable)
+ service = UICC_PIN_ENABLE;
+ else
+ 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;
-
- DBG("Fileid %04X not implemented", fileid);
+ }
error:
- CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+ CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
+ return;
}
-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 uicc_pin_change_resp(const GIsiMessage *msg, void *data)
{
- DBG("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, NULL, 0, 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);
-static void isi_read_file_cyclic(struct ofono_sim *sim, int fileid,
- int record, int length,
- ofono_sim_read_cb_t cb, void *data)
-{
- DBG("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
-}
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
-static void isi_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("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, data);
-}
+ if (g_isi_msg_error(msg) < 0)
+ goto error;
-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)
-{
- DBG("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, data);
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_CHANGE))
+ goto cont;
+
+ DBG("PIN change succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+cont:
+ 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 UICC_PIN_STATUS_AUTH_BLOCKED:
+ case UICC_PIN_STATUS_AUTH_FAILED:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) ==
+ UICC_PIN_STATUS_AUTH_RETRIES)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+error:
+ DBG("PIN change failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
-static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
- int length, const unsigned char *value,
- ofono_sim_write_cb_t cb, void *data)
+static void uicc_change_pin(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("Fileid %04X not implemented", fileid);
+ 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("old=%s, new=%s, PINID=%02x",
+ old, new, sd->current_pin_id);
+
+ if ((cbd) && (sd) && (sd->current_pin_id)) {
+ unsigned char service = UICC_PIN_CHANGE;
+ unsigned char oldlen = strlen(old);
+ unsigned char newlen = strlen(new);
+
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 2, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /* Must be fixed */
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_OLD, /* PIN qualifier */
+ oldlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ /* Subblock 2 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ /* Sub block length:
+ * "header" size + 1 (=trailing filler) + PIN length */
+ 16,
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_NEW, /* PIN qualifier */
+ newlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if ((oldlen < 4) || (oldlen > 8))
+ goto error;
+
+ if ((newlen < 4) || (newlen > 8))
+ goto error;
+
+ memmove(&msg[14], old, oldlen);
+ memmove(&msg[30], new, newlen);
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_pin_change_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("Error");
CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+ return;
}
-static void imsi_resp_cb(const GIsiMessage *msg, void *data)
+static void uicc_pin_send_puk_resp(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
- ofono_sim_imsi_cb_t cb = cbd->cb;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
- struct sim_imsi *resp;
- size_t len = sizeof(struct sim_imsi);
+ if (g_isi_msg_error(msg) < 0)
+ goto error;
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_UNBLOCK))
+ goto cont;
+
+ DBG("PIN reset succeeded");
+ /* Only PIN1 can be reseted, turns PIN query on */
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PUK] = FALSE;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
- char imsi[SIM_MAX_IMSI_LENGTH + 1];
- size_t i, j;
+cont:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
- if (!check_response_status(msg, SIM_IMSI_RESP_READ_IMSI, READ_IMSI))
- goto error;
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
- if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
- goto error;
+ 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);
- /* Ignore the low-order semi-octet of the first byte */
- imsi[0] = ((resp->imsi[0] & 0xF0) >> 4) + '0';
+ switch (status) {
+ case UICC_PIN_STATUS_AUTH_BLOCKED:
+ case UICC_PIN_STATUS_AUTH_FAILED:
+ DBG("Authentication method blocked");
+ break;
+ default:
- for (i = 1, j = 1; i < resp->length && j < SIM_MAX_IMSI_LENGTH; i++) {
- char nibble;
+ if ((status & 0xfff0) ==
+ UICC_PIN_STATUS_AUTH_RETRIES)
+ DBG("Attempts left %d", status & 0xf);
- imsi[j++] = (resp->imsi[i] & 0x0F) + '0';
- nibble = (resp->imsi[i] & 0xF0) >> 4;
- if (nibble != 0x0F)
- imsi[j++] = nibble + '0';
- }
+ break;
+ }
- imsi[j] = '\0';
- CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
- return;
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
error:
- CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+ DBG("PIN reset failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
-static void isi_read_imsi(struct ofono_sim *sim,
- ofono_sim_imsi_cb_t cb, void *data)
+static void uicc_pin_send_puk(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);
+ unsigned char service = UICC_PIN_UNBLOCK;
+ unsigned char pinlen = strlen(passwd);
+ uint8_t pin[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ uint8_t pukcode[10] = { 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0 };
+
+ uint8_t msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 2, /*number of subblocks*/
+ /* Subblock 1*/
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /*sb length, must be fixed*/
+ sd->current_pin_id, /* PIN id*/
+ UICC_PIN_NEW, /* PIN qualifier*/
+ pinlen /* PIN length*/
+ };
+ uint8_t msg2[] = {
+ /* Subblock 2*/
+ UICC_SB_PUK >> 8,
+ UICC_SB_PUK & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ sd->current_pin_id, /* PIN id*/
+ 8, /* PUK length*/
+ };
- const uint8_t msg[] = {
- SIM_IMSI_REQ_READ_IMSI,
- READ_IMSI
+ struct iovec iov[4] = {
+ { msg, sizeof(msg) },
+ { pin, 8 },
+ { msg2, sizeof(msg2) },
+ { pukcode, 10 }
};
- size_t len = sizeof(msg);
if (cbd == NULL || sd == NULL)
goto error;
- if (g_isi_client_send(sd->client, msg, len, imsi_resp_cb, cbd, g_free))
- return;
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+
+ if (strlen(puk) != 8)
+ goto error;
+
+ sd->current_pin_id = sd->pin1_id; /* No way to reset PIN2 */
+
+ memmove(pin, passwd, pinlen);
+ memmove(pukcode, puk, 8);
+
+ g_isi_client_vsend_with_timeout(sd->client, iov, 4, SIM_TIMEOUT,
+ uicc_pin_send_puk_resp, cbd,
+ g_free);
+ return;
error:
- CALLBACK_WITH_FAILURE(cb, NULL, data);
+ CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
+ return;
}
static void isi_sim_register(struct ofono_sim *sim)
@@ -414,34 +2569,125 @@ static void sim_ind_cb(const GIsiMessage *msg, void *data)
struct sim_data *sd = ofono_sim_get_data(sim);
uint8_t status;
- if (sd == NULL || g_isi_msg_id(msg) != SIM_IND || sd->registered)
- return;
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ uint8_t service_type;
+ uint8_t pin_id;
+
+ g_isi_msg_data_get_byte(msg, 0, &service_type);
+ g_isi_msg_data_get_byte(msg, 1, &pin_id);
+
+ switch (g_isi_msg_id(msg)) {
+
+ case UICC_CARD_IND:
+ ofono_sim_inserted_notify(sim, TRUE);
+
+ if ((service_type == UICC_CARD_READY) &&
+ (!sd->uicc_app_started)) {
+ DBG("UICC_CARD_IND activation");
+ uicc_application_list_req(sd->client, sim);
+ }
+ break;
+ case UICC_PIN_IND:
+ sd->pin_state_received = TRUE;
+ sd->passwd_required = FALSE;
+
+ switch (service_type) {
+ case UICC_PIN_VERIFY_NEEDED:
+ update_locked_pin((
+ struct ofono_sim_local *)sim,
+ UICC_PIN_VERIFY_NEEDED,
+ pin_id);
+ break;
+ case UICC_PIN_UNBLOCK_NEEDED:
+ update_locked_pin((
+ struct ofono_sim_local *)sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ pin_id);
+ break;
+ case UICC_PIN_PERMANENTLY_BLOCKED:
+ case UICC_PIN_VERIFIED:
+ default:
+ break;
+ }
+
+ break;
+ case UICC_IND:
+ DBG("UICC IND RECEIVED");
+
+ if (service_type == UICC_START_UP_COMPLETE)
+ sd->passwd_required = FALSE;
+
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (sd == NULL || g_isi_msg_id(msg) != SIM_IND ||
+ sd->registered)
+ return;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &status))
+ return;
+
+ switch (status) {
+ case SIM_ST_PIN:
+ isi_sim_register(sim);
+ break;
+
+ case SIM_ST_INFO:
+ isi_read_hplmn(sim);
+ break;
+ }
+ }
+}
+
+static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ GIsiModem *modem = g_isi_client_modem(sd->primary);
- if (!g_isi_msg_data_get_byte(msg, 0, &status))
+ if (g_isi_msg_error(msg) < 0)
return;
- switch (status) {
- case SIM_ST_PIN:
- isi_sim_register(sim);
- break;
+ ISI_VERSION_DBG(msg);
- case SIM_ST_INFO:
- isi_read_hplmn(sim);
- break;
+ sd->client = sd->primary;
+ sd->uicc_app_started = FALSE;
+ sd->pin_state_received = FALSE;
+ sd->passwd_required = TRUE;
+ sd->current_pin_id = 0x01;
+ sd->pin1_id = 0x01;
+ sd->pin2_id = 0x81;
+
+ g_isi_modem_set_sim(modem, sim);
+
+ if (!sd->uicc_app_started) {
+ DBG("Let's check if we have UICC applications");
+ uicc_application_list_req(sd->client, sim);
}
+ g_isi_client_destroy(sd->secondary);
}
static void sim_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_sim *sim = data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ GIsiModem *modem = g_isi_client_modem(sd->secondary);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ sd->client = sd->secondary;
+
+ g_isi_modem_set_sim(modem, sim);
+
/* Check if SIM is ready by reading HPLMN */
isi_read_hplmn(sim);
+
+ g_isi_client_destroy(sd->primary);
}
static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
@@ -454,16 +2700,32 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
if (sd == NULL)
return -ENOMEM;
- sd->client = g_isi_client_create(modem, PN_SIM);
- if (sd->client == NULL) {
+ sd->primary = g_isi_client_create(modem, PN_UICC);
+
+ if (sd->primary == NULL) {
+ g_free(sd);
+ return -ENOMEM;
+ }
+
+ sd->secondary = g_isi_client_create(modem, PN_SIM);
+
+ if (sd->secondary == NULL) {
g_free(sd);
return -ENOMEM;
}
ofono_sim_set_data(sim, sd);
- g_isi_client_ind_subscribe(sd->client, SIM_IND, sim_ind_cb, sim);
- g_isi_client_verify(sd->client, sim_reachable_cb, sim, NULL);
+ g_isi_client_ind_subscribe(sd->secondary, SIM_IND, sim_ind_cb, sim);
+
+ g_isi_client_ind_subscribe(sd->primary, UICC_IND, sim_ind_cb, sim);
+ g_isi_client_ind_subscribe(sd->primary, UICC_CARD_IND, sim_ind_cb, sim);
+ g_isi_client_ind_subscribe(sd->primary, UICC_PIN_IND, sim_ind_cb, sim);
+ g_isi_client_ind_subscribe(sd->primary, UICC_APPLICATION_IND,
+ sim_ind_cb, sim);
+
+ g_isi_client_verify(sd->primary, uicc_reachable_cb, sim, NULL);
+ g_isi_client_verify(sd->secondary, sim_reachable_cb, sim, NULL);
return 0;
}
@@ -471,13 +2733,23 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
static void isi_sim_remove(struct ofono_sim *sim)
{
struct sim_data *data = ofono_sim_get_data(sim);
-
- ofono_sim_set_data(sim, NULL);
+ GIsiModem *modem = g_isi_client_modem(data->client);
if (data == NULL)
return;
- g_isi_client_destroy(data->client);
+ g_isi_modem_set_sim(modem, NULL);
+
+ if (g_isi_client_resource(data->client) == PN_UICC) {
+ data->uicc_app_started = FALSE;
+ data->pin_state_received = FALSE;
+ data->passwd_required = TRUE;
+
+ g_isi_client_destroy(data->client);
+ } else
+ g_isi_client_destroy(data->client);
+
+ ofono_sim_set_data(sim, NULL);
g_free(data);
}
@@ -493,8 +2765,18 @@ 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 = uicc_passwd_state_query,
+ .send_passwd = uicc_pin_enter,
+ .reset_passwd = uicc_pin_send_puk,
+ .change_passwd = uicc_change_pin,
+ .lock = uicc_pin_enable,
};
+struct ofono_sim_driver *get_sim_driver_func(void)
+{
+ return &driver;
+}
+
void isi_sim_init(void)
{
ofono_sim_driver_register(&driver);
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (7 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
` (8 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 23551 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-settings.c | 711 +++++++++++++++++++++++++++++++++++++-
drivers/isimodem/call.h | 9 +
drivers/isimodem/debug.c | 4 +
drivers/isimodem/ss.h | 22 ++
4 files changed, 728 insertions(+), 18 deletions(-)
diff --git a/drivers/isimodem/call-settings.c b/drivers/isimodem/call-settings.c
index 89270e9..ed3d11e 100644
--- a/drivers/isimodem/call-settings.c
+++ b/drivers/isimodem/call-settings.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
@@ -45,6 +46,7 @@
struct settings_data {
GIsiClient *client;
+ int clir_status;
};
static void update_status_mask(unsigned int *mask, int bsc)
@@ -88,7 +90,6 @@ static void update_status_mask(unsigned int *mask, int bsc)
break;
}
}
-
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
{
if (g_isi_msg_error(msg) < 0) {
@@ -104,6 +105,59 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
return TRUE;
}
+static void clip_query_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter;
+ struct isi_cb_data *cbd = data;
+
+ ofono_call_settings_status_cb_t cb = cbd->cb;
+ uint8_t service;
+ guint32 mask = 0;
+
+ if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &service) ||
+ service != SS_INTERROGATION)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 6);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+
+ if (ss_status & SS_GSM_PROVISIONED)
+ mask = 1;
+ }
+ break;
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+ }
+
+ DBG("status_mask %d\n", mask);
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+}
+
+
static gboolean decode_gsm_bsc_info(GIsiSubBlockIter *iter, uint32_t *mask)
{
uint8_t num;
@@ -136,23 +190,628 @@ static void query_resp_cb(const GIsiMessage *msg, void *data)
goto error;
for (g_isi_sb_iter_init(&iter, msg, 6);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) == SS_GSM_BSC_INFO) {
+ if (!decode_gsm_bsc_info(&iter, &mask))
+ goto error;
+
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ return;
+ } else if (g_isi_sb_iter_get_id(&iter) == SS_STATUS_RESULT) {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ if (ss_status & SS_GSM_PROVISIONED)
+ mask = 1;
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ return;
+ }
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+}
+
+static void isi_clip_query(struct ofono_call_settings *cs,
+ ofono_call_settings_status_cb_t cb, void *data)
+{
+ struct settings_data *sd = ofono_call_settings_get_data(cs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+ unsigned char msg[] = {
+ SS_SERVICE_REQ,
+ SS_INTERROGATION,
+ SS_ALL_TELE_AND_BEARER,
+ SS_GSM_CLIP >> 8, /* Supplementary services */
+ SS_GSM_CLIP & 0xFF, /* code */
+ SS_SEND_ADDITIONAL_INFO,
+ 0 /* Subblock count */
+ };
+ DBG("");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg),
+ clip_query_cb, cbd, g_free))
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ g_free(cbd);
+}
+
+static void set_clir_status(struct settings_data *sd, const int value)
+{
+ DBG("Setting CLIR status to %i", value);
+ sd->clir_status = value;
+}
+
+static int get_clir_status(struct settings_data *sd)
+{
+
+ DBG("Getting CLIR status %i", sd->clir_status);
+
+ switch (sd->clir_status) {
+ case OFONO_CLIR_OPTION_INVOCATION:
+ break;
+ case OFONO_CLIR_OPTION_SUPPRESSION:
+ break;
+ default:
+ sd->clir_status = OFONO_CLIR_OPTION_DEFAULT;
+ break;
+ }
+ return sd->clir_status;
+}
+
+static gboolean check_clir_info(const GIsiMessage *msg, GIsiSubBlockIter* iter)
+{
+ GIsiMessage info_msg;
+ GIsiSubBlockIter iter_info;
+ guint8 clir_option = 0;
+ void *info = NULL;
+
+ /*
+ * GIsiMessage function adds 2 to data pointer and
+ * removes 2 from len
+ */
+
+ info_msg.addr = NULL;
+ info_msg.error = 0;
+
+ if (!g_isi_sb_iter_get_data(iter, &info, 4))
+ goto error;
+ info_msg.data = info - 2;
+ info_msg.len = msg->len - 6 + 2;
+
+ for (g_isi_sb_iter_init(&iter_info, &info_msg, 0);
+ g_isi_sb_iter_is_valid(&iter_info);
+ g_isi_sb_iter_next(&iter_info)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(
+ g_isi_sb_iter_get_id(&iter_info)));
+
+ switch (g_isi_sb_iter_get_id(&iter_info)) {
+ case SS_GSM_CLIR_INFO: {
+ if (!g_isi_sb_iter_get_byte(&iter_info,
+ &clir_option, 2))
+ goto error;
+ }
+ break;
+ default:
+ break;
+ }
+ DBG("CLIR_OPTION=%d", clir_option);
+ }
+ return TRUE;
+error:
+ return FALSE;
+}
+
+
+static void clir_set_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter;
+ struct isi_cb_data *cbd = data;
+ ofono_call_settings_set_cb_t cb = cbd->cb;
+ struct settings_data *sd = ofono_call_settings_get_data(cbd->user);
+ gint override = OFONO_CLIR_OPTION_DEFAULT;
+ gint network = CLIR_STATUS_UNKNOWN;
+ uint8_t service;
+
+ if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &service) ||
+ service != SS_INTERROGATION)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 6);
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
- if (g_isi_sb_iter_get_id(&iter) != SS_GSM_BSC_INFO)
- continue;
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+
+ if (!(ss_status & SS_GSM_PROVISIONED))
+ network = CLIR_STATUS_NOT_PROVISIONED;
+ }
+ break;
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+ case SS_GSM_GENERIC_SERVICE_INFO: {
+ guint8 ss_status = 0;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ if (!(ss_status & SS_GSM_PROVISIONED))
+ network = CLIR_STATUS_NOT_PROVISIONED;
+
+ if (!check_clir_info(msg, &iter))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+ goto error;
- if (!decode_gsm_bsc_info(&iter, &mask))
+ if (network != CLIR_STATUS_NOT_PROVISIONED) {
+ DBG("CLIR set successfully.");
+ set_clir_status(sd,
+ OFONO_CLIR_OPTION_INVOCATION);
+
+ } else {
+ DBG("CLIR option not supported by network "
+ "provider.");
+ }
+ }
+ break;
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+ }
+
+ DBG("override=%d, network=%d\n", override, network);
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void isi_clir_set(struct ofono_call_settings *cs,
+ int mode,
+ ofono_call_settings_set_cb_t cb,
+ void *data)
+{
+ struct settings_data *sd = ofono_call_settings_get_data(cs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+ int result = 0;
+ /*
+ * CLIR cannot be activated in Network, but we can override it
+ * using local settings - 3GPP TS 24.081 Chapter 2.5
+ */
+
+ switch (mode) {
+ case(OFONO_CLIR_OPTION_DEFAULT):
+ set_clir_status(sd, OFONO_CLIR_OPTION_DEFAULT);
+ break;
+ /* CLIR enabled (number not shown) */
+ case(OFONO_CLIR_OPTION_INVOCATION): {
+ /*
+ * We send interrogation request to check if Network
+ * has CLIR option provisioned.
+ */
+ unsigned char msg[] = {
+ SS_SERVICE_REQ,
+ SS_INTERROGATION,
+ SS_ALL_TELE_AND_BEARER,
+ SS_GSM_CLIR >> 8, /* Supplementary services */
+ SS_GSM_CLIR & 0xFF, /* code */
+ SS_SEND_ADDITIONAL_INFO,
+ 0 /* Subblock count */
+ };
+
+ DBG("Attempting to set the CLIR - checking Network Settings");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg),
+ clir_set_cb, cbd, g_free))
+
+ return;
+ else
goto error;
+ }
+ break;
+ case(OFONO_CLIR_OPTION_SUPPRESSION): /* CLIR disabled (number shown) */
+ set_clir_status(sd, OFONO_CLIR_OPTION_SUPPRESSION);
+ break;
+ default:
+ DBG("CLIR mode not supported %d", mode);
+ break;
+ }
+
+ if (result == EXIT_FAILURE)
+ goto error;
+
+ DBG("CLIR set to mode: %d", mode);
+ CALLBACK_WITH_SUCCESS(cb, data);
+ goto out;
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+out:
+ g_free(cbd);
+ return;
+}
+
+static void clir_query_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter, iter_info;
+ struct isi_cb_data *cbd = data;
+ ofono_call_settings_clir_cb_t cb = cbd->cb;
+ struct settings_data *sd = ofono_call_settings_get_data(cbd->user);
+ uint8_t service;
+ gint override = OFONO_CLIR_OPTION_DEFAULT;
+ gint network = CLIR_STATUS_UNKNOWN;
- CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+
+ if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &service) ||
+ service != SS_INTERROGATION)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 6);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+
+ if (!(ss_status & SS_GSM_PROVISIONED))
+ network = CLIR_STATUS_NOT_PROVISIONED;
+ }
+ break;
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+ case SS_GSM_GENERIC_SERVICE_INFO: {
+ guint8 ss_status = 0;
+ guint8 clir_option = 0;
+ void *info = NULL;
+ GIsiMessage info_msg;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ if (!(ss_status & SS_GSM_PROVISIONED))
+ network = CLIR_STATUS_NOT_PROVISIONED;
+
+ if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+ goto error;
+
+ info_msg.addr = NULL;
+ info_msg.error = 0;
+ /* GIsiMessage function adds 2 to data pointer and
+ * removes 2 from len */
+ info_msg.data = info - 2;
+ info_msg.len = msg->len - 6 + 2;
+
+ for (g_isi_sb_iter_init(&iter_info, &info_msg, 0);
+ g_isi_sb_iter_is_valid(&iter_info);
+ g_isi_sb_iter_next(&iter_info)) {
+ uint8_t id = g_isi_sb_iter_get_id(&iter_info);
+ DBG("Sub-sub-block %d", id);
+
+ switch (id) {
+ case SS_GSM_CLIR_INFO: {
+ if (!g_isi_sb_iter_get_byte(&iter_info,
+ &clir_option, 2))
+ goto error;
+ break;
+ }
+ default:
+ break;
+ }
+
+ DBG("SS_STATUS_RESULT=%d, CLIR_OPTION=%d",
+ ss_status, clir_option);
+ }
+
+ if (network != CLIR_STATUS_NOT_PROVISIONED) {
+ switch (clir_option) {
+ case SS_GSM_CLI_PERMANENT:
+ network =
+ CLIR_STATUS_PROVISIONED_PERMANENT;
+ break;
+ case SS_GSM_DEFAULT_RESTRICTED:
+ break;
+ case SS_GSM_CLI_DEFAULT_ALLOWED:
+ network =
+ CLIR_STATUS_TEMPORARY_ALLOWED;
+ break;
+ case SS_GSM_OVERRIDE_ENABLED:
+ override =
+ OFONO_CLIR_OPTION_SUPPRESSION;
+ break;
+ case SS_GSM_OVERRIDE_DISABLED:
+ override =
+ OFONO_CLIR_OPTION_INVOCATION;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+ }
+ /*
+ * CLIR cannot be activated,registrated in Network, but we can override
+ * it using local settings - 33GPP TS 24.081 Chapter 2.5
+ * we have to read status and pass override parameter to Ofono
+ */
+
+ if (network != CLIR_STATUS_NOT_PROVISIONED) {
+ override = get_clir_status(sd);
+ DBG("CLIR mode queried %d\n", override);
+ }
+
+ DBG("override=%d, network=%d\n", override, network);
+ CALLBACK_WITH_SUCCESS(cb, override, network, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, override, network, cbd->data);
+}
+
+static void isi_clir_query(struct ofono_call_settings *cs,
+ ofono_call_settings_clir_cb_t cb, void *data)
+{
+ struct settings_data *sd = ofono_call_settings_get_data(cs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+ int override = 0, network = 2;
+ unsigned char msg[] = {
+ SS_SERVICE_REQ,
+ SS_INTERROGATION,
+ SS_ALL_TELE_AND_BEARER,
+ SS_GSM_CLIR >> 8, /* Supplementary services */
+ SS_GSM_CLIR & 0xFF, /* code */
+ SS_SEND_ADDITIONAL_INFO,
+ 0 /* Subblock count */
+ };
+ DBG("");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg),
+ clir_query_cb, cbd, g_free))
return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, override, network, data);
+ g_free(cbd);
+}
+
+static void colp_query_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter;
+ struct isi_cb_data *cbd = data;
+ ofono_call_settings_status_cb_t cb = cbd->cb;
+ uint8_t service;
+ guint32 mask = 0;
+
+ if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &service) ||
+ service != SS_INTERROGATION)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 6);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+
+ if (ss_status & SS_GSM_PROVISIONED)
+ mask = 1;
+ }
+ break;
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+ case SS_GSM_BSC_INFO: {
+ guint8 bsc;
+ guint8 count;
+ guint8 i;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+ goto error;
+
+ for (i = 0; i < count; i++) {
+ if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+ goto error;
+
+ update_status_mask(&mask, bsc);
+ }
+
+ break;
+ }
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
}
+ DBG("status_mask %d\n", mask);
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ return;
error:
CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
}
+static void isi_colp_query(struct ofono_call_settings *cs,
+ ofono_call_settings_status_cb_t cb, void *data)
+{
+ struct settings_data *sd = ofono_call_settings_get_data(cs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+ unsigned char msg[] = {
+ SS_SERVICE_REQ,
+ SS_INTERROGATION,
+ SS_ALL_TELE_AND_BEARER,
+ SS_GSM_COLP >> 8, /* Supplementary services */
+ SS_GSM_COLP & 0xFF, /* code */
+ SS_SEND_ADDITIONAL_INFO,
+ 0 /* Subblock count */
+ };
+ DBG("");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg),
+ colp_query_cb, cbd, g_free))
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ g_free(cbd);
+}
+
+static void colr_query_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter;
+ struct isi_cb_data *cbd = data;
+ ofono_call_settings_status_cb_t cb = cbd->cb;
+ uint8_t service;
+ guint32 mask = 0;
+
+ if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &service) ||
+ service != SS_INTERROGATION)
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 6);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ DBG("Sub-block %s",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
+
+ if (ss_status & SS_GSM_PROVISIONED)
+ mask = 1;
+ }
+ break;
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+ case SS_GSM_BSC_INFO: {
+ guint8 bsc;
+ guint8 count;
+ guint8 i;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+ goto error;
+ for (i = 0; i < count; i++) {
+ if (!g_isi_sb_iter_get_byte(&iter, &bsc,
+ 3 + i))
+ goto error;
+
+ update_status_mask(&mask, bsc);
+ }
+
+ break;
+ }
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+ }
+
+ DBG("status_mask %d\n", mask);
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+}
+
+static void isi_colr_query(struct ofono_call_settings *cs,
+ ofono_call_settings_status_cb_t cb, void *data)
+{
+ struct settings_data *sd = ofono_call_settings_get_data(cs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+ unsigned char msg[] = {
+ SS_SERVICE_REQ,
+ SS_INTERROGATION,
+ SS_ALL_TELE_AND_BEARER,
+ SS_GSM_COLR >> 8, /* Supplementary services */
+ SS_GSM_COLR & 0xFF, /* code */
+ SS_SEND_ADDITIONAL_INFO,
+ 0 /* Subblock count */
+ };
+ DBG("");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg),
+ colr_query_cb, cbd, g_free))
+
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ g_free(cbd);
+}
+
static void isi_cw_query(struct ofono_call_settings *cs, int cls,
ofono_call_settings_status_cb_t cb, void *data)
{
@@ -205,17 +864,31 @@ static void set_resp_cb(const GIsiMessage *msg, void *data)
if (g_isi_sb_iter_get_id(&iter) != SS_GSM_DATA)
continue;
- if (!g_isi_sb_iter_get_byte(&iter, &status, 2))
- goto error;
+ if (g_isi_sb_iter_get_id(&iter) == SS_GSM_DATA) {
+ if (!g_isi_sb_iter_get_byte(&iter, &status, 2))
+ goto error;
- if ((status & SS_GSM_ACTIVE) && (service == SS_DEACTIVATION))
- goto error;
+ if ((status & SS_GSM_ACTIVE) &&
+ (service == SS_DEACTIVATION))
+ goto error;
- if (!(status & SS_GSM_ACTIVE) && (service == SS_ACTIVATION))
- goto error;
+ if (!(status & SS_GSM_ACTIVE) &&
+ (service == SS_ACTIVATION))
+ goto error;
- CALLBACK_WITH_SUCCESS(cb, cbd->data);
- return;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+ } else if (g_isi_sb_iter_get_id(&iter) == SS_GSM_DATA) {
+ guint8 ss_status;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+ }
}
error:
@@ -273,10 +946,12 @@ static int isi_call_settings_probe(struct ofono_call_settings *cs,
return -ENOMEM;
sd->client = g_isi_client_create(modem, PN_SS);
+
if (sd->client == NULL) {
g_free(sd);
return -ENOMEM;
}
+ sd->clir_status = OFONO_CLIR_OPTION_DEFAULT;
ofono_call_settings_set_data(cs, sd);
@@ -302,11 +977,11 @@ static struct ofono_call_settings_driver driver = {
.name = "isimodem",
.probe = isi_call_settings_probe,
.remove = isi_call_settings_remove,
- .clip_query = NULL,
- .colp_query = NULL,
- .clir_query = NULL,
- .colr_query = NULL,
- .clir_set = NULL,
+ .clip_query = isi_clip_query,
+ .colp_query = isi_colp_query,
+ .clir_query = isi_clir_query,
+ .colr_query = isi_colr_query,
+ .clir_set = isi_clir_set,
.cw_query = isi_cw_query,
.cw_set = isi_cw_set
};
diff --git a/drivers/isimodem/call.h b/drivers/isimodem/call.h
index 05f05a5..84f4e04 100644
--- a/drivers/isimodem/call.h
+++ b/drivers/isimodem/call.h
@@ -402,6 +402,15 @@ enum {
CALL_DTMF_DISABLE_TONE_IND_SEND = 0x02,
};
+/* 27.007 Section 7.7 */
+enum clir_status {
+ CLIR_STATUS_NOT_PROVISIONED = 0,
+ CLIR_STATUS_PROVISIONED_PERMANENT,
+ CLIR_STATUS_UNKNOWN,
+ CLIR_STATUS_TEMPORARY_RESTRICTED,
+ CLIR_STATUS_TEMPORARY_ALLOWED
+};
+
#ifdef __cplusplus
};
#endif
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index 89e4573..33e4dcb 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -95,10 +95,14 @@ const char *ss_subblock_name(enum ss_subblock value)
_(SS_GSM_FORWARDING_FEATURE);
_(SS_GSM_DATA);
_(SS_GSM_BSC_INFO);
+ _(SS_GSM_GENERIC_SERVICE_INFO);
+ _(SS_GSM_CLIR_INFO);
_(SS_GSM_PASSWORD_INFO);
_(SS_GSM_INDICATE_PASSWORD_ERROR);
_(SS_GSM_INDICATE_ERROR);
_(SS_GSM_ADDITIONAL_INFO);
+ _(SS_GSM_BARRING_INFO);
+ _(SS_GSM_BARRING_FEATURE);
_(SS_GSM_USSD_STRING);
}
return "SS_<UNKNOWN>";
diff --git a/drivers/isimodem/ss.h b/drivers/isimodem/ss.h
index 5cd86e9..8a2942e 100644
--- a/drivers/isimodem/ss.h
+++ b/drivers/isimodem/ss.h
@@ -94,6 +94,12 @@ enum ss_codes {
SS_GSM_BARR_OUT_INTER = 331,
SS_GSM_BARR_OUT_INTER_EXC_HOME = 332,
SS_GSM_BARR_ALL_IN_ROAM = 351,
+ SS_GSM_CLIP = 0x001E,
+ SS_GSM_CLIR = 0x001F,
+ SS_GSM_COLP = 0x004C,
+ SS_GSM_COLR = 0x004D,
+ SS_GSM_CNAP = 0x012C,
+ SS_GSM_ECT = 0x0060
};
enum ss_response_data {
@@ -106,9 +112,13 @@ enum ss_subblock {
SS_GSM_PASSWORD = 0x03,
SS_GSM_FORWARDING_INFO = 0x04,
SS_GSM_FORWARDING_FEATURE = 0x05,
+ SS_GSM_BARRING_INFO = 0x06,
+ SS_GSM_BARRING_FEATURE = 0x07,
SS_GSM_DATA = 0x08,
SS_GSM_BSC_INFO = 0x09,
+ SS_GSM_GENERIC_SERVICE_INFO = 0x0A,
SS_GSM_PASSWORD_INFO = 0x0B,
+ SS_GSM_CLIR_INFO = 0x0C,
SS_GSM_INDICATE_PASSWORD_ERROR = 0x0D,
SS_GSM_INDICATE_ERROR = 0x0E,
SS_GSM_ADDITIONAL_INFO = 0x2F,
@@ -122,4 +132,16 @@ enum ss_isi_cause {
SS_GSM_QUIESCENT = 0x08,
};
+enum ss_gsm_cli_restriction_option {
+ SS_GSM_CLI_PERMANENT = 0x00,
+ SS_GSM_DEFAULT_RESTRICTED = 0x01,
+ SS_GSM_CLI_DEFAULT_ALLOWED = 0x02,
+ SS_GSM_OVERRIDE_ENABLED = 0x03,
+ SS_GSM_OVERRIDE_DISABLED = 0x04
+};
+
+enum ss_constants {
+ SS_UNDEFINED_TIME = 0x00,
+};
+
#endif /* __ISIMODEM_SS_H */
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (8 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
` (7 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 14044 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call.h | 82 ++++++++++++++++-
drivers/isimodem/voicecall.c | 218 +++++++++++++++++++++++++++++++++---------
2 files changed, 253 insertions(+), 47 deletions(-)
diff --git a/drivers/isimodem/call.h b/drivers/isimodem/call.h
index 84f4e04..9c854a4 100644
--- a/drivers/isimodem/call.h
+++ b/drivers/isimodem/call.h
@@ -27,6 +27,8 @@ extern "C" {
#endif
#define PN_CALL 0x01
+#define PN_MODEM_CALL 0xC9
+#define CALL_MODEM_PROP_PRESENT_DEFAULT 0x00
enum call_message_id {
CALL_CREATE_REQ = 0x01,
@@ -333,6 +335,7 @@ enum call_subblock {
CALL_MODE_CHANGE_INFO = 0x36,
CALL_ADDITIONAL_PARAMS = 0x37,
CALL_DSAC_INFO = 0x38,
+ CALL_LINE_ID = 0x47,
};
enum call_id {
@@ -351,6 +354,10 @@ enum call_id {
CALL_ID_ALL = 0xF0,
};
+enum call_dtmf_pause_values {
+ CALL_DTMF_PAUSE_1S = 0x01
+};
+
enum call_mode {
CALL_MODE_EMERGENCY = 0x00,
CALL_MODE_SPEECH = 0x01,
@@ -369,6 +376,12 @@ enum {
CALL_GSM_PRESENTATION_DEFAULT = 0x07,
};
+enum call_modem_line_id {
+ CALL_MODEM_PRESENT_DEFAULT = 0x00,
+ CALL_MODEM_PRESENT_ALLOWED = 0x01,
+ CALL_MODEM_PRESENT_RESTRICTED = 0x02
+};
+
enum call_operation {
CALL_OP_HOLD = 0x01,
CALL_OP_RETRIEVE = 0x02,
@@ -402,9 +415,76 @@ enum {
CALL_DTMF_DISABLE_TONE_IND_SEND = 0x02,
};
+enum call_notification_indicator {
+ CALL_NOTIFY_USER_SUSPENDED = 0x00,
+ CALL_NOTIFY_USER_RESUMED = 0x01,
+ CALL_NOTIFY_BEARER_CHANGE = 0x02
+};
+
+enum call_mmi_ss_codes {
+ CALL_SSC_ALL_FWDS = 0x0002,
+ CALL_SSC_ALL_COND_FWD = 0x0004,
+ CALL_SSC_CFU = 0x0015,
+ CALL_SSC_CFB = 0x0043,
+ CALL_SSC_CFNRY = 0x003D,
+ CALL_SSC_CFGNC = 0x003E,
+ CALL_SSC_OUTGOING_BARR_SERV = 0x014D,
+ CALL_SSC_INCOMING_BARR_SERV = 0x0161,
+ CALL_SSC_CALL_WAITING = 0x002B,
+ CALL_SSC_CLIR = 0x001F,
+ CALL_SSC_ETC = 0x0060,
+ CALL_SSC_MPTY = 0xFFFE,
+ CALL_SSC_CALL_HOLD = 0xFFFF
+};
+
+enum call_ss_status {
+ CALL_SS_STATUS_ACTIVE = 0x01,
+ CALL_SS_STATUS_REGISTERED = 0x02,
+ CALL_SS_STATUS_PROVISIONED = 0x04,
+ CALL_SS_STATUS_QUIESCENT = 0x08
+};
+
+enum call_ss_notification {
+ CALL_SSN_INCOMING_IS_FWD = 0x01,
+ CALL_SSN_INCOMING_FWD = 0x02,
+ CALL_SSN_OUTGOING_FWD = 0x04
+};
+
+enum call_ss_indicator {
+ CALL_SSI_CALL_IS_WAITING = 0x01,
+ CALL_SSI_MPTY = 0x02,
+ CALL_SSI_CLIR_SUPPR_REJ = 0x04
+};
+
+enum call_ss_hold_indicator {
+ CALL_HOLD_IND_RETRIEVED = 0x00,
+ CALL_HOLD_IND_ON_HOLD = 0x01
+};
+
+enum call_ss_ect_indicator {
+ CALL_ECT_CALL_STATE_ALERT = 0x00,
+ CALL_ECT_CALL_STATE_ACTIVE = 0x01
+};
+
+enum call_notification_sb_values {
+ CALL_SB_NOTIFY = 0xB1,
+ CALL_SB_SS_NOTIFY = 0xB2,
+ CALL_SB_SS_CODE = 0xB3,
+ CALL_SB_SS_STATUS = 0xB4,
+ CALL_SB_SS_NOTIFY_INDICATOR = 0xB5,
+ CALL_SB_SS_HOLD_INDICATOR = 0xB6,
+ CALL_SB_SS_ECT_INDICATOR = 0xB7,
+ CALL_SB_REMOTE_ADDRESS = 0xA6,
+ CALL_SB_REMOTE_SUBADDRESS = 0xA7,
+ CALL_SB_CUG_INFO = 0xA0,
+ CALL_SB_ORIGIN_INFO = 0x0E,
+ CALL_SB_ALERTING_PATTERN = 0xA1,
+ CALL_SB_ALERTING_INFO = 0x0C
+};
+
/* 27.007 Section 7.7 */
enum clir_status {
- CLIR_STATUS_NOT_PROVISIONED = 0,
+ CLIR_STATUS_NOT_PROVISIONED = 0,
CLIR_STATUS_PROVISIONED_PERMANENT,
CLIR_STATUS_UNKNOWN,
CLIR_STATUS_TEMPORARY_RESTRICTED,
diff --git a/drivers/isimodem/voicecall.c b/drivers/isimodem/voicecall.c
index 0a32f27..750707d 100644
--- a/drivers/isimodem/voicecall.c
+++ b/drivers/isimodem/voicecall.c
@@ -57,7 +57,7 @@ struct isi_call {
uint8_t addr_type;
uint8_t presentation;
uint8_t reason;
- char address[20];
+ char address[30];
char addr_pad[4];
};
@@ -82,10 +82,12 @@ struct call_info {
struct isi_voicecall {
GIsiClient *client;
-
+ GIsiClient *primary;
+ GIsiClient *secondary;
struct isi_call_req_ctx *queue;
-
struct isi_call calls[8];
+ void *control_req_irc;
+
};
typedef void isi_call_req_step(struct isi_call_req_ctx *ctx, int reason);
@@ -395,7 +397,7 @@ static struct ofono_call isi_call_as_ofono_call(const struct isi_call *call)
ocall.direction = call->mode_info & CALL_MODE_ORIGINATOR;
ocall.status = isi_call_status_to_clcc(call);
- memcpy(number->number, call->address, sizeof(number->number));
+ memmove(number->number, call->address, sizeof(number->number));
number->type = 0x80 | call->addr_type;
ocall.clip_validity = call->presentation & 3;
@@ -546,26 +548,66 @@ static struct isi_call_req_ctx *isi_call_create_req(struct ofono_voicecall *ovc,
ofono_voicecall_cb_t cb,
void *data)
{
+ struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
size_t addr_len = strlen(address);
size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
- size_t i, offset = 3 + 4 + 8 + 6;
- uint8_t req[3 + 4 + 8 + 6 + 40] = {
- CALL_CREATE_REQ,
- 0, /* No id */
- 3, /* Mode, Clir, Number */
+ size_t origin_size = (g_isi_client_resource(ivc->client) ==
+ PN_MODEM_CALL) ? 4 : 8;
+ size_t i, offset = 3 + 4 + origin_size + 6;
+ size_t rlen = 3 + 4 + origin_size + sub_len;
+ uint8_t req[3 + 4 + origin_size + 6 + 40];
+
+ memset(req, 0, 3 + 4 + origin_size + 6 + 40);
+
+ if (g_isi_client_resource(ivc->client) == PN_MODEM_CALL) {
+ req[0] = CALL_CREATE_REQ;
+ req[1] = 0; /* No id */
+ req[2] = 3; /* Mode, Clir, Number */
/* MODE SB */
- CALL_MODE, 4, CALL_MODE_SPEECH, CALL_MODE_INFO_NONE,
+ req[3] = CALL_MODE;
+ req[4] = 4;
+ req[5] = CALL_MODE_SPEECH;
+ req[6] = 0;
/* ORIGIN_INFO SB */
- CALL_ORIGIN_INFO, 8, presentation, 0, 0, 0, 0, 0,
+ req[7] = CALL_LINE_ID;
+ req[8] = origin_size;
+ req[9] = presentation;
+ req[10] = 0;
/* DESTINATION_ADDRESS SB */
- CALL_DESTINATION_ADDRESS,
- sub_len,
- addr_type & 0x7F,
- 0, 0,
- addr_len,
+ req[11] = CALL_DESTINATION_ADDRESS;
+ req[12] = sub_len;
+ req[13] = addr_type & 0x7F;
+ req[14] = 0;
+ req[15] = 0;
+ req[16] = addr_len;
/* uint16_t addr[20] */
- };
- size_t rlen = 3 + 4 + 8 + sub_len;
+ } else {
+ req[0] = CALL_CREATE_REQ;
+ req[1] = 0; /* No id */
+ req[2] = 3; /* Mode, Clir, Number */
+ /* MODE SB */
+ req[3] = CALL_MODE;
+ req[4] = 4;
+ req[5] = CALL_MODE_SPEECH;
+ req[6] = CALL_MODE_INFO_NONE;
+ /* ORIGIN_INFO SB */
+ req[7] = CALL_ORIGIN_INFO;
+ req[8] = origin_size;
+ req[9] = presentation;
+ req[10] = 0;
+ req[11] = 0;
+ req[12] = 0;
+ req[13] = 0;
+ req[14] = 0;
+ /* DESTINATION_ADDRESS SB */
+ req[15] = CALL_DESTINATION_ADDRESS;
+ req[16] = sub_len;
+ req[17] = addr_type & 0x7F;
+ req[18] = 0;
+ req[19] = 0;
+ req[20] = addr_len;
+ /* uint16_t addr[20] */
+ }
if (addr_len > 20) {
CALLBACK_WITH_FAILURE(cb, data);
@@ -726,7 +768,8 @@ error:
isi_ctx_return_failure(irc);
}
-static struct isi_call_req_ctx *isi_call_release_req(struct ofono_voicecall *ovc,
+static struct isi_call_req_ctx *isi_call_release_req(
+ struct ofono_voicecall *ovc,
uint8_t call_id,
enum call_cause_type cause_type,
uint8_t cause,
@@ -770,7 +813,8 @@ static void isi_call_status_resp(const GIsiMessage *msg, void *data)
break;
case CALL_ADDR_AND_STATUS_INFO:
- call = isi_call_addr_and_status_info_sb_proc(ivc, &iter);
+ call = isi_call_addr_and_status_info_sb_proc(ivc,
+ &iter);
if (call)
isi_call_notify(ovc, call);
break;
@@ -836,12 +880,13 @@ error:
isi_ctx_return_failure(irc);
}
-static struct isi_call_req_ctx *isi_call_control_req(struct ofono_voicecall *ovc,
- uint8_t call_id,
- enum call_operation op,
- uint8_t info,
- ofono_voicecall_cb_t cb,
- void *data)
+static struct isi_call_req_ctx *isi_call_control_req(
+ struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ enum call_operation op,
+ uint8_t info,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
const uint8_t req[] = {
CALL_CONTROL_REQ,
@@ -856,12 +901,13 @@ static struct isi_call_req_ctx *isi_call_control_req(struct ofono_voicecall *ovc
cb, data);
}
-static struct isi_call_req_ctx *isi_call_deflect_req(struct ofono_voicecall *ovc,
- uint8_t call_id,
- uint8_t address_type,
- const char address[21],
- ofono_voicecall_cb_t cb,
- void *data)
+static struct isi_call_req_ctx *isi_call_deflect_req(
+ struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ uint8_t address_type,
+ const char address[21],
+ ofono_voicecall_cb_t cb,
+ void *data)
{
size_t addr_len = strlen(address);
size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
@@ -893,6 +939,37 @@ static struct isi_call_req_ctx *isi_call_deflect_req(struct ofono_voicecall *ovc
return isi_call_req(ovc, req, rlen, isi_call_control_resp, cb, data);
}
+static void isi_call_control_ind_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_voicecall *ovc = data;
+ struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+ GIsiSubBlockIter iter;
+ uint8_t cause_type = 0, cause = 0;
+
+ if (ivc == NULL || g_isi_msg_id(msg) != CALL_CONTROL_IND)
+ return;
+
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != CALL_CAUSE)
+ continue;
+ if (!g_isi_sb_iter_get_byte(&iter, &cause_type, 2) ||
+ !g_isi_sb_iter_get_byte(&iter, &cause, 3))
+ return;
+ }
+
+ if (ivc->control_req_irc) {
+ if (!cause)
+ isi_ctx_return_success(ivc->control_req_irc);
+ else
+ isi_ctx_return_failure(ivc->control_req_irc);
+
+ ivc->control_req_irc = NULL;
+ }
+}
+
static void isi_call_dtmf_send_resp(const GIsiMessage *msg, void *data)
{
struct isi_call_req_ctx *irc = data;
@@ -924,11 +1001,12 @@ error:
isi_ctx_return_failure(irc);
}
-static struct isi_call_req_ctx *isi_call_dtmf_send_req(struct ofono_voicecall *ovc,
- uint8_t call_id,
- const char *string,
- ofono_voicecall_cb_t cb,
- void *data)
+static struct isi_call_req_ctx *isi_call_dtmf_send_req(
+ struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ const char *string,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
size_t str_len = strlen(string);
size_t sub_len = 4 + ((2 * str_len + 3) & ~3);
@@ -963,18 +1041,23 @@ static void isi_dial(struct ofono_voicecall *ovc,
enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
void *data)
{
- unsigned char presentation = CALL_GSM_PRESENTATION_DEFAULT;
+ unsigned char presentation;
+ struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
switch (clir) {
- case OFONO_CLIR_OPTION_DEFAULT:
- presentation = CALL_GSM_PRESENTATION_DEFAULT;
- break;
case OFONO_CLIR_OPTION_INVOCATION:
presentation = CALL_PRESENTATION_RESTRICTED;
break;
case OFONO_CLIR_OPTION_SUPPRESSION:
presentation = CALL_PRESENTATION_ALLOWED;
break;
+ case OFONO_CLIR_OPTION_DEFAULT:
+ default:
+ presentation = (g_isi_client_resource(ivc->client) ==
+ PN_MODEM_CALL) ?
+ CALL_MODEM_PROP_PRESENT_DEFAULT :
+ CALL_GSM_PRESENTATION_DEFAULT;
+ break;
}
isi_call_create_req(ovc, presentation, number->type, number->number,
@@ -1275,7 +1358,7 @@ static void isi_send_tones(struct ofono_voicecall *ovc, const char *tones,
isi_call_dtmf_send_req(ovc, CALL_ID_ALL, tones, cb, data);;
}
-static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
+static void isi_primary_call_verify_cb(const GIsiMessage *msg, void *data)
{
struct ofono_voicecall *ovc = data;
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
@@ -1285,8 +1368,42 @@ static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
ISI_VERSION_DBG(msg);
+ ivc->client = ivc->primary;
+ g_isi_client_destroy(ivc->secondary);
+
g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
- isi_call_status_ind_cb, ovc);
+ isi_call_status_ind_cb, ovc);
+ g_isi_client_ind_subscribe(ivc->client, CALL_CONTROL_IND,
+ isi_call_control_ind_cb, ovc);
+
+ g_isi_client_ind_subscribe(ivc->client, CALL_TERMINATED_IND,
+ isi_call_terminated_ind_cb, ovc);
+
+ if (!isi_call_status_req(ovc, CALL_ID_ALL,
+ CALL_STATUS_MODE_ADDR_AND_ORIGIN,
+ NULL, NULL))
+ DBG("Failed to request call status");
+
+ ofono_voicecall_register(ovc);
+}
+
+static void isi_secondary_call_verify_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_voicecall *ovc = data;
+ struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+
+ ivc->client = ivc->secondary;
+ g_isi_client_destroy(ivc->primary);
+
+ g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
+ isi_call_status_ind_cb, ovc);
+ g_isi_client_ind_subscribe(ivc->client, CALL_CONTROL_IND,
+ isi_call_control_ind_cb, ovc);
g_isi_client_ind_subscribe(ivc->client, CALL_TERMINATED_IND,
isi_call_terminated_ind_cb, ovc);
@@ -1313,15 +1430,24 @@ static int isi_voicecall_probe(struct ofono_voicecall *ovc,
for (id = 0; id <= 7; id++)
ivc->calls[id].id = id;
- ivc->client = g_isi_client_create(modem, PN_CALL);
- if (ivc->client == NULL) {
+ ivc->primary = g_isi_client_create(modem, PN_MODEM_CALL);
+ if (ivc->primary == NULL) {
+ g_free(ivc);
+ return -ENOMEM;
+ }
+ ivc->secondary = g_isi_client_create(modem, PN_CALL);
+ if (ivc->secondary == NULL) {
g_free(ivc);
+ g_isi_client_destroy(ivc->primary);
return -ENOMEM;
}
ofono_voicecall_set_data(ovc, ivc);
- g_isi_client_verify(ivc->client, isi_call_verify_cb, ovc, NULL);
+ g_isi_client_verify(ivc->primary, isi_primary_call_verify_cb, ovc,
+ NULL);
+ g_isi_client_verify(ivc->secondary, isi_secondary_call_verify_cb, ovc,
+ NULL);
return 0;
}
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (9 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
` (6 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2518 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/ussd.c | 36 ++++++++++++++++++++++++++++++------
1 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/drivers/isimodem/ussd.c b/drivers/isimodem/ussd.c
index d649484..ce402f1 100644
--- a/drivers/isimodem/ussd.c
+++ b/drivers/isimodem/ussd.c
@@ -55,6 +55,7 @@ struct ussd_info {
struct ussd_data {
GIsiClient *client;
+ GIsiVersion version;
int mt_session;
};
@@ -166,7 +167,10 @@ static void isi_request(struct ofono_ussd *ussd, int dcs,
{
struct ussd_data *ud = ofono_ussd_get_data(ussd);
struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
- const uint8_t msg[] = {
+ const uint8_t padding_bytes[] = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint8_t iov_size = 2;
+
+ uint8_t msg[] = {
SS_GSM_USSD_SEND_REQ,
ud->mt_session
? SS_GSM_USSD_MT_REPLY
@@ -178,15 +182,31 @@ static void isi_request(struct ofono_ussd *ussd, int dcs,
len, /* string length */
/* USSD string goes here */
};
- const struct iovec iov[2] = {
- { (uint8_t *) msg, sizeof(msg) },
- { (uint8_t *) pdu, len }
- };
+ struct iovec iov[3] = { { 0, 0 }, { 0, 0 }, { 0, 0 } };
if (cbd == NULL || ud == NULL)
goto error;
- if (g_isi_client_vsend(ud->client, iov, 2,
+ if (ud->version.major == 14 && ud->version.minor >= 1) {
+ uint8_t filled_len = (4 + len + 3) & ~3;
+ struct iovec t_iov[3] = {
+ { (uint8_t *) msg, sizeof(msg) },
+ { (uint8_t *)pdu, len },
+ { (uint8_t *) padding_bytes, (filled_len - len - 4) }
+ };
+ iov_size = 3;
+ memmove(iov, t_iov, sizeof(struct iovec) * iov_size);
+
+ msg[4] = filled_len;
+ } else {
+ struct iovec t_iov[2] = {
+ { (uint8_t *) msg, sizeof(msg) },
+ { (uint8_t *) pdu, len }
+ };
+ memmove(iov, t_iov, sizeof(struct iovec) * iov_size);
+ }
+
+ if (g_isi_client_vsend(ud->client, iov, iov_size,
ussd_send_resp_cb, cbd, g_free))
return;
@@ -228,6 +248,9 @@ static void ussd_reachable_cb(const GIsiMessage *msg, void *data)
ISI_VERSION_DBG(msg);
+ ud->version.major = g_isi_msg_version_major(msg);
+ ud->version.minor = g_isi_msg_version_minor(msg);
+
g_isi_client_ind_subscribe(ud->client, SS_GSM_USSD_RECEIVE_IND,
ussd_ind_cb, ussd);
@@ -241,6 +264,7 @@ static int isi_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
struct ussd_data *ud;
ud = g_try_new0(struct ussd_data, 1);
+
if (ud == NULL)
return -ENOMEM;
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (10 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 15:46 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
` (5 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3551 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
SS_GSM_BSC_INFO added.
---
drivers/isimodem/call-barring.c | 99 ++++++++++++++++++++++++++++++++++----
1 files changed, 88 insertions(+), 11 deletions(-)
diff --git a/drivers/isimodem/call-barring.c b/drivers/isimodem/call-barring.c
index a78b762..a1d9a13 100644
--- a/drivers/isimodem/call-barring.c
+++ b/drivers/isimodem/call-barring.c
@@ -190,6 +190,40 @@ static void update_status_mask(unsigned int *mask, int bsc)
}
}
+static gboolean decode_gsm_barring_info(const void *restrict data, size_t len,
+ guint32 *mask)
+{
+ GIsiSubBlockIter iter;
+
+ for (g_isi_sb_iter_init(&iter, data, 0);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case SS_GSM_BARRING_FEATURE: {
+ uint8_t status;
+ uint8_t bsc;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &bsc, 2) ||
+ !g_isi_sb_iter_get_byte(&iter, &status,
+ 3))
+ return FALSE;
+
+ if (status & SS_GSM_ACTIVE)
+ update_status_mask(mask, bsc);
+
+ break;
+ }
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
static void query_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -197,9 +231,6 @@ static void query_resp_cb(const GIsiMessage *msg, void *data)
GIsiSubBlockIter iter;
uint32_t mask = 0;
uint8_t type;
- uint8_t count = 0;
- uint8_t bsc = 0;
- uint8_t i;
if (!check_response_status(msg, SS_SERVICE_COMPLETED_RESP))
goto error;
@@ -214,18 +245,65 @@ static void query_resp_cb(const GIsiMessage *msg, void *data)
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
- if (g_isi_sb_iter_get_id(&iter) != SS_GSM_BSC_INFO)
- continue;
+ switch (g_isi_sb_iter_get_id(&iter)) {
- if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
- goto error;
+ case SS_STATUS_RESULT: {
+ guint8 ss_status;
- for (i = 0; i < count; i++) {
+ if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+ goto error;
+
+ DBG("SS_STATUS_RESULT=%d", ss_status);
- if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+ if (ss_status & SS_GSM_ACTIVE)
+ mask = 1;
+
+ break;
+ }
+
+ case SS_GSM_BARRING_INFO: {
+ void *info = NULL;
+ size_t infolen;
+
+ if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+ goto error;
+
+ infolen = g_isi_sb_iter_get_len(&iter) - 4;
+
+ if (!decode_gsm_barring_info(info, infolen, &mask))
+ goto error;
+
+ break;
+ }
+
+ case SS_GSM_BSC_INFO: {
+
+ guint8 count = 0;
+ guint8 i;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
goto error;
- update_status_mask(&mask, bsc);
+ for (i = 0; i < count; i++) {
+
+ guint8 bsc = 0;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+ goto error;
+
+ update_status_mask(&mask, bsc);
+ }
+ break;
+ }
+
+ case SS_GSM_ADDITIONAL_INFO:
+ break;
+
+ default:
+ DBG("Skipping sub-block: %s (%zd bytes)",
+ ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
}
}
@@ -342,7 +420,6 @@ static void reachable_cb(const GIsiMessage *msg, void *data)
ofono_call_barring_register(barr);
}
-
static int isi_call_barring_probe(struct ofono_call_barring *barr,
unsigned int vendor, void *user)
{
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (11 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 16:36 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
` (4 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3096 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-forwarding.c | 29 +++++++++++++++++++++++++----
1 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/drivers/isimodem/call-forwarding.c b/drivers/isimodem/call-forwarding.c
index 89a03dc..687f975 100644
--- a/drivers/isimodem/call-forwarding.c
+++ b/drivers/isimodem/call-forwarding.c
@@ -46,6 +46,7 @@
struct forw_data {
GIsiClient *client;
+ GIsiVersion version;
};
struct forw_info {
@@ -230,11 +231,15 @@ static void isi_registration(struct ofono_call_forwarding *cf, int type,
/* Followed by number in UCS-2, zero sub address bytes, and 0
* to 3 bytes of filler */
- DBG("forwarding type %d class %d\n", type, cls);
if (cbd == NULL || fd == NULL || strlen(number->number) > 28)
goto error;
+ DBG("forwarding type %d class %d\n", type, cls);
+
+ if (fd->version.major == 14 && fd->version.minor >= 1)
+ msg[10] = SS_UNDEFINED_TIME;
+
ss_code = forw_type_to_isi_code(type);
if (ss_code < 0)
goto error;
@@ -248,6 +253,10 @@ static void isi_registration(struct ofono_call_forwarding *cf, int type,
msg[8] = 6 + 2 * strlen(number->number) + num_filler;
+ /* Time must not be set for any other than NoReply for ISI2.5 */
+ if (ss_code == SS_GSM_FORW_NO_REPLY)
+ msg[10] = time;
+
ucs2 = g_convert(number->number, strlen(number->number), "UCS-2BE",
"UTF-8//TRANSLIT", NULL, NULL, NULL);
if (ucs2 == NULL)
@@ -330,9 +339,10 @@ error:
static void query_resp_cb(const GIsiMessage *msg, void *data)
{
-
struct isi_cb_data *cbd = data;
ofono_call_forwarding_query_cb_t cb = cbd->cb;
+ struct ofono_call_forwarding *cf = cbd->user;
+ struct forw_data *fd = ofono_call_forwarding_get_data(cf);
GIsiSubBlockIter iter;
struct ofono_call_forwarding_condition list = {
@@ -366,8 +376,14 @@ static void query_resp_cb(const GIsiMessage *msg, void *data)
&number))
goto error;
- /* As in 27.007 section 7.11 */
- list.status = status & SS_GSM_ACTIVE;
+ if (fd->version.major == 14 && fd->version.minor >= 1) {
+ list.status = status & (SS_GSM_ACTIVE |
+ SS_GSM_REGISTERED |
+ SS_GSM_PROVISIONED);
+ } else {
+ /* As in 27.007 section 7.11 */
+ list.status = status & SS_GSM_ACTIVE;
+ }
list.time = noreply;
list.phone_number.type = ton | 0x80;
@@ -426,12 +442,16 @@ error:
static void reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_call_forwarding *cf = data;
+ struct forw_data *fd = ofono_call_forwarding_get_data(cf);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ fd->version.major = g_isi_msg_version_major(msg);
+ fd->version.minor = g_isi_msg_version_minor(msg);
+
ofono_call_forwarding_register(cf);
}
@@ -447,6 +467,7 @@ static int isi_call_forwarding_probe(struct ofono_call_forwarding *cf,
return -ENOMEM;
fd->client = g_isi_client_create(modem, PN_SS);
+
if (fd->client == NULL) {
g_free(fd);
return -ENOMEM;
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (12 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-03-03 15:46 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5 Andreas Westin
` (3 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 12700 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-forwarding.c | 1 -
drivers/isimodem/ssn.c | 406 +++++++++++++++++++++++++++++++++++-
2 files changed, 401 insertions(+), 6 deletions(-)
diff --git a/drivers/isimodem/call-forwarding.c b/drivers/isimodem/call-forwarding.c
index 687f975..05b304f 100644
--- a/drivers/isimodem/call-forwarding.c
+++ b/drivers/isimodem/call-forwarding.c
@@ -467,7 +467,6 @@ static int isi_call_forwarding_probe(struct ofono_call_forwarding *cf,
return -ENOMEM;
fd->client = g_isi_client_create(modem, PN_SS);
-
if (fd->client == NULL) {
g_free(fd);
return -ENOMEM;
diff --git a/drivers/isimodem/ssn.c b/drivers/isimodem/ssn.c
index 068e5e8..225e5e0 100644
--- a/drivers/isimodem/ssn.c
+++ b/drivers/isimodem/ssn.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
@@ -32,20 +33,403 @@
#include <glib.h>
#include <gisi/client.h>
+#include <gisi/iter.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/ssn.h>
+#include "call.h"
#include "isimodem.h"
#include "ss.h"
+#include "isiutil.h"
+#include "debug.h"
+
+#define NOT_3GGP_NOTIFICATION -1
+#define PN_SS 0x06
+
+/* TS 27.007 Supplementary service notifications +CSSN */
+enum ss_cssi {
+ SS_MO_UNCONDITIONAL_FORWARDING = 0,
+ SS_MO_CONDITIONAL_FORWARDING = 1,
+ SS_MO_CALL_FORWARDED = 2,
+ SS_MO_CALL_WAITING = 3,
+ SS_MO_CUG_CALL = 4,
+ SS_MO_OUTGOING_BARRING = 5,
+ SS_MO_INCOMING_BARRING = 6,
+ SS_MO_CLIR_SUPPRESSION_REJECTED = 7,
+ SS_MO_CALL_DEFLECTED = 8,
+};
+
+enum ss_cssu {
+ SS_MT_CALL_FORWARDED = 0,
+ SS_MT_CUG_CALL = 1,
+ SS_MT_VOICECALL_ON_HOLD = 2,
+ SS_MT_VOICECALL_RETRIEVED = 3,
+ SS_MT_MULTIPARTY_VOICECALL = 4,
+ SS_MT_VOICECALL_HOLD_RELEASED = 5,
+ SS_MT_FORWARD_CHECK_SS_MESSAGE = 6,
+ SS_MT_VOICECALL_IN_TRANSFER = 7,
+ SS_MT_VOICECALL_TRANSFERRED = 8,
+ SS_MT_CALL_DEFLECTED = 9,
+};
struct ssn_data {
GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
+};
+
+struct isi_ssn_prop {
+ char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1];
+ int type;
+ uint16_t cug_index;
+};
+
+struct isi_ssn {
+ GIsiClient *client;
+ struct isi_call_req_context *queue;
};
+static void isi_cm_sb_rem_address_sb_proc(struct isi_ssn_prop *ssn_prop,
+ GIsiSubBlockIter const *sb)
+{
+ uint8_t addr_type, addr_len;
+ char *address;
+ DBG("CALL_SB_REMOTE_ADDRESS");
+
+ if (!g_isi_sb_iter_get_byte(sb, &addr_type, 2) ||
+ /* address type */
+ /* presentation indicator */
+ /* fillerbyte */
+ !g_isi_sb_iter_get_byte(sb, &addr_len, 5) ||
+ !g_isi_sb_iter_get_alpha_tag(sb, &address, 2 *
+ addr_len, 6))
+ return;
+
+ strncpy(ssn_prop->number, address, addr_len);
+
+ g_free(address);
+}
+
+static void isi_ssn_notify_ofono(void *_ssn, int cssi, int cssu,
+ struct isi_ssn_prop *ssn_prop)
+{
+ struct ofono_phone_number *phone_nr =
+ (struct ofono_phone_number *) ssn_prop;
+
+ if (cssi != NOT_3GGP_NOTIFICATION)
+ ofono_ssn_cssi_notify(_ssn, cssi, ssn_prop->cug_index);
+
+ if (cssu != NOT_3GGP_NOTIFICATION)
+ ofono_ssn_cssu_notify(_ssn, cssi, ssn_prop->cug_index,
+ phone_nr);
+}
+
+static void isi_ssn_call_modem_sb_notify(GIsiSubBlockIter const *sb)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property == CALL_NOTIFY_USER_SUSPENDED)
+ DBG("CALL_NOTIFY_USER_SUSPENDED");
+
+ if (sb_property == CALL_NOTIFY_USER_RESUMED)
+ DBG("CALL_NOTIFY_USER_RESUMED");
+
+ if (sb_property == CALL_NOTIFY_BEARER_CHANGE)
+ DBG("CALL_NOTIFY_BEARER_CHANGE");
+}
+
+static void isi_ssn_call_modem_sb_ss_code(GIsiSubBlockIter const *sb,
+ int *cssi_p, int *cssu_p)
+{
+ uint16_t sb_property;
+ g_isi_sb_iter_get_word(sb, &sb_property, 2);
+
+ switch (sb_property) {
+ case(CALL_SSC_ALL_FWDS):
+ DBG("Call forwarding is active");
+ break;
+ case(CALL_SSC_ALL_COND_FWD): {
+ *(cssi_p) = SS_MO_CONDITIONAL_FORWARDING;
+ DBG("Some of conditional call forwardings active");
+ }
+ break;
+ case(CALL_SSC_CFU): {
+ *(cssi_p) = SS_MO_UNCONDITIONAL_FORWARDING;
+ DBG("Unconditional call forwarding is active");
+ }
+ break;
+ case(CALL_SSC_CFB):
+ DBG("Unknown notification #1");
+ break;
+ case(CALL_SSC_CFNRY):
+ DBG("Unknown notification #2");
+ break;
+ case(CALL_SSC_CFGNC):
+ DBG("Unknown notification #3");
+ break;
+ case(CALL_SSC_OUTGOING_BARR_SERV): {
+ *(cssi_p) = SS_MO_OUTGOING_BARRING;
+ DBG("Outgoing calls are barred");
+ }
+ break;
+ case(CALL_SSC_INCOMING_BARR_SERV): {
+ *(cssi_p) = SS_MO_INCOMING_BARRING;
+ DBG("Incoming calls are barred");
+ }
+ break;
+ case(CALL_SSC_CALL_WAITING):
+ DBG("Incoming calls are barred");
+ break;
+ case(CALL_SSC_CLIR):
+ DBG("CLIR connected unknown indication.");
+ break;
+ case(CALL_SSC_ETC):
+ DBG("Unknown notification #4");
+ break;
+ case(CALL_SSC_MPTY): {
+ *(cssu_p) = SS_MT_MULTIPARTY_VOICECALL;
+ DBG("Multiparty call entered.");
+ }
+ break;
+ case(CALL_SSC_CALL_HOLD): {
+ *(cssu_p) = SS_MT_VOICECALL_HOLD_RELEASED;
+ DBG("Call on hold has been released.");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void isi_ssn_call_modem_sb_ss_status(GIsiSubBlockIter const *sb)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property & CALL_SS_STATUS_ACTIVE)
+ DBG("CALL_SS_STATUS_ACTIVE");
+
+ if (sb_property & CALL_SS_STATUS_REGISTERED)
+ DBG("CALL_SS_STATUS_REGISTERED");
+
+ if (sb_property & CALL_SS_STATUS_PROVISIONED)
+ DBG("CALL_SS_STATUS_PROVISIONED");
+
+ if (sb_property & CALL_SS_STATUS_QUIESCENT)
+ DBG("CALL_SS_STATUS_QUIESCENT");
+}
+
+static void isi_ssn_call_modem_sb_ss_notify(GIsiSubBlockIter const *sb,
+ int *cssi_p, int *cssu_p)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property & CALL_SSN_INCOMING_IS_FWD) {
+ *(cssu_p) = SS_MT_CALL_FORWARDED;
+ DBG("This is a forwarded call #1.");
+ }
+
+ if (sb_property & CALL_SSN_INCOMING_FWD)
+ DBG("This is a forwarded call #2.");
+
+ if (sb_property & CALL_SSN_OUTGOING_FWD) {
+ *(cssi_p) = SS_MO_CALL_FORWARDED;
+ DBG("Call has been forwarded.");
+ }
+}
+
+static void isi_ssn_call_modem_sb_ss_notify_ind(GIsiSubBlockIter const *sb,
+ int *cssi_p)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property & CALL_SSI_CALL_IS_WAITING) {
+ *(cssi_p) = SS_MO_CALL_WAITING;
+ DBG("Call is waiting.");
+ }
+
+ if (sb_property & CALL_SSI_MPTY)
+ DBG("Multiparty call.");
+
+ if (sb_property & CALL_SSI_CLIR_SUPPR_REJ) {
+ *(cssi_p) = SS_MO_CLIR_SUPPRESSION_REJECTED;
+ DBG("CLIR suppression rejected.");
+ }
+}
+
+static void isi_ssn_call_modem_sb_ss_hold(GIsiSubBlockIter const *sb,
+ int *cssu_p)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property & CALL_HOLD_IND_RETRIEVED) {
+ *(cssu_p) = SS_MT_VOICECALL_RETRIEVED;
+ DBG("Call has been retrieved.");
+ }
+
+ if (sb_property & CALL_HOLD_IND_ON_HOLD) {
+ *(cssu_p) = SS_MT_VOICECALL_ON_HOLD;
+ DBG("Call has been put on hold.");
+ }
+}
+
+static void isi_ssn_call_modem_sb_ss_ect_ind(GIsiSubBlockIter const *sb,
+ int *cssu_p)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+ if (sb_property & CALL_ECT_CALL_STATE_ALERT) {
+ *(cssu_p) = SS_MT_VOICECALL_IN_TRANSFER;
+ DBG("Call is being connected with the remote party");
+ DBG("in alerting state.");
+ }
+
+ if (sb_property & CALL_ECT_CALL_STATE_ACTIVE) {
+ *(cssu_p) = SS_MT_VOICECALL_TRANSFERRED;
+ DBG("Call has been connected with the other remote");
+ DBG("party in explicit call transfer operation.");
+ }
+}
+
+static int isi_ssn_call_modem_sb_cug_info(GIsiSubBlockIter const *sb,
+ struct isi_ssn_prop *ssn_prop)
+{
+ uint8_t sb_property;
+ g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+ DBG("CALL_SB_CUG_INFO: This is a CUG Call.");
+ DBG("Preferential CUG: 0x%x,", sb_property);
+ g_isi_sb_iter_get_byte(sb, &sb_property, 3);
+ DBG("Cug Output Access: 0x%x,", sb_property);
+ g_isi_sb_iter_get_word(sb, &ssn_prop->cug_index, 4);
+ DBG("Cug Call Index: 0x%x,", ssn_prop->cug_index);
+ return SS_MO_CUG_CALL;
+}
+
+
+static void isi_callmodem_notif_ind_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_ssn *ssn = data;
+ struct isi_ssn *issn = ofono_ssn_get_data(ssn);
+ struct isi_ssn_prop *ssn_prop = g_try_new0(struct isi_ssn_prop, 1);
+ struct {
+ uint8_t message_id, call_id, sub_blocks;
+ } const *m = data;
+ int cssi = NOT_3GGP_NOTIFICATION;
+ int cssu = NOT_3GGP_NOTIFICATION;
+ GIsiSubBlockIter sb[1];
+ DBG("Received CallServer notification.");
+
+ if (g_isi_msg_data_len(msg) < 3)
+ goto out;
+
+ if (issn->client == NULL)
+ goto out;
+
+ for (g_isi_sb_iter_init(sb, data, (sizeof *m));
+ g_isi_sb_iter_is_valid(sb);
+ g_isi_sb_iter_next(sb)) {
+ switch (g_isi_sb_iter_get_id(sb)) {
+ case CALL_SB_NOTIFY:
+ isi_ssn_call_modem_sb_notify(sb);
+ break;
+ case CALL_SB_SS_CODE:
+ isi_ssn_call_modem_sb_ss_code(sb, &cssi, &cssu);
+ break;
+ case CALL_SB_SS_STATUS:
+ isi_ssn_call_modem_sb_ss_status(sb);
+ break;
+ case CALL_SB_SS_NOTIFY:
+ isi_ssn_call_modem_sb_ss_notify(sb, &cssi, &cssu);
+ break;
+ case CALL_SB_SS_NOTIFY_INDICATOR:
+ isi_ssn_call_modem_sb_ss_notify_ind(sb, &cssi);
+ break;
+ case CALL_SB_SS_HOLD_INDICATOR:
+ isi_ssn_call_modem_sb_ss_hold(sb, &cssu);
+ break;
+ case CALL_SB_SS_ECT_INDICATOR:
+ isi_ssn_call_modem_sb_ss_ect_ind(sb, &cssu);
+ break;
+ case CALL_SB_REMOTE_ADDRESS:
+ isi_cm_sb_rem_address_sb_proc(ssn_prop, sb);
+ break;
+ case CALL_SB_REMOTE_SUBADDRESS:
+ break;
+ case CALL_SB_CUG_INFO:
+ cssu = isi_ssn_call_modem_sb_cug_info(sb, ssn_prop);
+ break;
+ case CALL_SB_ORIGIN_INFO:
+ break;
+ case CALL_SB_ALERTING_PATTERN:
+ break;
+ case CALL_SB_ALERTING_INFO:
+ break;
+ }
+ }
+
+ isi_ssn_notify_ofono(ssn, cssi, cssu, ssn_prop);
+out:
+ g_free(ssn_prop);
+}
+
+static gboolean isi_ssn_register(gpointer user)
+{
+ struct ofono_ssn *ssn = user;
+ struct ssn_data *sd = ofono_ssn_get_data(ssn);
+ DBG("");
+
+ g_isi_client_ind_subscribe(sd->client, CALL_GSM_NOTIFICATION_IND,
+ isi_callmodem_notif_ind_cb, ssn);
+
+ ofono_ssn_register(user);
+
+ return FALSE;
+}
+
+static void ssn_primary_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_ssn *ssn = data;
+ struct ssn_data *sd = ofono_ssn_get_data(ssn);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ if (sd == NULL)
+ return;
+ sd->client = sd->primary;
+ g_isi_client_destroy(sd->secondary);
+
+ ISI_VERSION_DBG(msg);
+
+ g_idle_add(isi_ssn_register, ssn);
+}
+
+static void ssn_secondary_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_ssn *ssn = data;
+ struct ssn_data *sd = ofono_ssn_get_data(ssn);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ if (sd == NULL)
+ return;
+
+ sd->client = sd->secondary;
+ g_isi_client_destroy(sd->primary);
+
+ ISI_VERSION_DBG(msg);
+}
+
static int isi_ssn_probe(struct ofono_ssn *ssn, unsigned int vendor,
- void *user)
+ void *user)
{
GIsiModem *modem = user;
struct ssn_data *sd;
@@ -54,12 +438,24 @@ static int isi_ssn_probe(struct ofono_ssn *ssn, unsigned int vendor,
if (sd == NULL)
return -ENOMEM;
- sd->client = g_isi_client_create(modem, PN_SS);
+ sd->primary = g_isi_client_create(modem, PN_MODEM_CALL);
+
+ if (sd->primary == NULL) {
+ g_free(sd);
+ return -ENOMEM;
+ }
+
+ sd->secondary = g_isi_client_create(modem, PN_SS);
+
if (sd->client == NULL) {
g_free(sd);
return -ENOMEM;
}
+ g_isi_client_verify(sd->primary, ssn_primary_reachable_cb, ssn, NULL);
+ g_isi_client_verify(sd->secondary, ssn_secondary_reachable_cb, ssn,
+ NULL);
+
ofono_ssn_set_data(ssn, sd);
return 0;
@@ -79,9 +475,9 @@ static void isi_ssn_remove(struct ofono_ssn *ssn)
}
static struct ofono_ssn_driver driver = {
- .name = "isimodem",
- .probe = isi_ssn_probe,
- .remove = isi_ssn_remove
+ .name = "isimodem",
+ .probe = isi_ssn_probe,
+ .remove = isi_ssn_remove
};
void isi_ssn_init(void)
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (13 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
` (2 subsequent siblings)
17 siblings, 1 reply; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 5183 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/isimodem/debug.h | 1 +
drivers/isimodem/sms.h | 34 ++++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index 33e4dcb..1fd2226 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -53,6 +53,7 @@ const char *pn_resource_name(int value)
_(PN_GSS);
_(PN_GPDS);
_(PN_WRAN);
+ _(PN_UICC);
}
return "PN_<UNKNOWN>";
}
@@ -218,6 +219,47 @@ const char *mce_rf_state_name(enum mce_rf_state value)
return "MCE_RF<UNKNOWN>";
}
+const char *uicc_message_id_name(enum uicc_message_id value)
+{
+ switch (value) {
+ _(UICC_REQ);
+ _(UICC_RESP);
+ _(UICC_IND);
+ _(UICC_CARD_REQ);
+ _(UICC_CARD_RESP);
+ _(UICC_CARD_IND);
+ _(UICC_APPLICATION_REQ);
+ _(UICC_APPLICATION_RESP);
+ _(UICC_APPLICATION_IND);
+ _(UICC_PIN_REQ);
+ _(UICC_PIN_RESP);
+ _(UICC_PIN_IND);
+ _(UICC_APPL_CMD_REQ);
+ _(UICC_APPL_CMD_RESP);
+ _(UICC_APPL_CMD_IND);
+ _(UICC_CONNECTOR_REQ);
+ _(UICC_CONNECTOR_RESP);
+ _(UICC_CAT_REQ);
+ _(UICC_CAT_RESP);
+ _(UICC_CAT_IND);
+ _(UICC_APDU_REQ);
+ _(UICC_APDU_RESP);
+ _(UICC_APDU_RESET_IND);
+ _(UICC_REFRESH_REQ);
+ _(UICC_REFRESH_RESP);
+ _(UICC_REFRESH_IND);
+ _(UICC_SIMLOCK_REQ);
+ _(UICC_SIMLOCK_RESP);
+ _(UICC_APDU_SAP_REQ);
+ _(UICC_APDU_SAP_RESP);
+ _(UICC_APDU_SAP_IND);
+ _(UICC_PWR_CTRL_REQ);
+ _(UICC_PWR_CTRL_RESP);
+ _(UICC_PWR_CTRL_IND);
+ }
+ return "UICC_<UNKNOWN>";
+}
+
const char *uicc_status_name(uint8_t value)
{
switch (value) {
@@ -403,6 +445,15 @@ const char *sms_message_id_name(enum sms_message_id value)
_(SMS_GSM_CB_ROUTING_RESP);
_(SMS_GSM_CB_ROUTING_NTF);
_(SMS_MESSAGE_SEND_STATUS_IND);
+ _(SMS_SETTINGS_UPDATE_REQ);
+ _(SMS_SETTINGS_UPDATE_RESP);
+ _(SMS_SETTINGS_READ_REQ);
+ _(SMS_SETTINGS_READ_RESP);
+ _(SMS_RECEIVED_MSG_REPORT_REQ);
+ _(SMS_RECEIVED_MSG_REPORT_RESP);
+ _(SMS_RECEIVE_MESSAGE_REQ);
+ _(SMS_RECEIVE_MESSAGE_RESP);
+ _(SMS_RECEIVED_MSG_IND);
_(SMS_COMMON_MESSAGE);
}
return "SMS_<UNKNOWN>";
@@ -420,6 +471,9 @@ const char *sms_subblock_name(enum sms_subblock value)
_(SMS_GSM_ROUTING);
_(SMS_GSM_CB_MESSAGE);
_(SMS_GSM_TPDU);
+ _(SMS_GSM_TPDU_25);
+ _(SMS_GSM_ROUTE_INFO);
+ _(SMS_GSM_PARAMETERS);
_(SMS_COMMON_DATA);
_(SMS_ADDRESS);
}
@@ -1224,6 +1278,8 @@ static const char *res_to_name(uint8_t res, uint8_t id)
return gss_message_id_name(id);
case PN_GPDS:
return gpds_message_id_name(id);
+ case PN_UICC:
+ return uicc_message_id_name(id);
}
return "UNKNOWN";
}
diff --git a/drivers/isimodem/debug.h b/drivers/isimodem/debug.h
index db01f04..5648f7a 100644
--- a/drivers/isimodem/debug.h
+++ b/drivers/isimodem/debug.h
@@ -48,6 +48,7 @@ const char *mce_message_id_name(enum mce_message_id value);
const char *mce_modem_state_name(enum mce_modem_state value);
const char *mce_status_info(enum mce_status_info value);
+const char *uicc_message_id_name(enum uicc_message_id value);
const char *uicc_subblock_name(uint8_t value);
const char *uicc_status_name(uint8_t value);
diff --git a/drivers/isimodem/sms.h b/drivers/isimodem/sms.h
index cbfb124..a51adf2 100644
--- a/drivers/isimodem/sms.h
+++ b/drivers/isimodem/sms.h
@@ -55,6 +55,7 @@ enum sms_isi_cause {
};
enum sms_isi_cause_type {
+ SMS_CAUSE_TYPE_COMMON = 0x00,
SMS_CAUSE_TYPE_GSM = 0x01,
};
@@ -125,6 +126,15 @@ enum sms_message_id {
SMS_GSM_CB_ROUTING_RESP = 0x0C,
SMS_GSM_CB_ROUTING_NTF = 0x0D,
SMS_MESSAGE_SEND_STATUS_IND = 0x22,
+ SMS_SETTINGS_UPDATE_REQ = 0x30,
+ SMS_SETTINGS_UPDATE_RESP = 0x31,
+ SMS_SETTINGS_READ_REQ = 0x32,
+ SMS_SETTINGS_READ_RESP = 0x33,
+ SMS_RECEIVED_MSG_REPORT_REQ = 0x3B,
+ SMS_RECEIVED_MSG_REPORT_RESP = 0x3C,
+ SMS_RECEIVE_MESSAGE_REQ = 0x41,
+ SMS_RECEIVE_MESSAGE_RESP = 0x42,
+ SMS_RECEIVED_MSG_IND = 0x43,
SMS_COMMON_MESSAGE = 0xF0
};
@@ -138,6 +148,9 @@ enum sms_subblock {
SMS_GSM_ROUTING = 0x0D,
SMS_GSM_CB_MESSAGE = 0x0E,
SMS_GSM_TPDU = 0x11,
+ SMS_GSM_TPDU_25 = 0x001C,
+ SMS_GSM_ROUTE_INFO = 0x0023,
+ SMS_GSM_PARAMETERS = 0x0031,
SMS_COMMON_DATA = 0x80,
SMS_ADDRESS = 0x82,
};
@@ -175,6 +188,7 @@ enum sms_address_type {
SMS_UNICODE_ADDRESS = 0x00,
SMS_GSM_0340_ADDRESS = 0x01,
SMS_GSM_0411_ADDRESS = 0x02,
+ SMS_SMSC_ADDRESS = 0x02
};
enum sms_sender_type {
@@ -192,6 +206,26 @@ enum sms_subject_list_type {
SMS_CB_NOT_ALLOWED_IDS_LIST = 0x01
};
+enum sms_reception_command {
+ SMS_RECEPTION_ACTIVATE = 0x01,
+ SMS_RECEPTION_DEACTIVATE = 0x02
+};
+
+enum sms_reception_status {
+ SMS_RECEPTION_ACTIVE = 0x01,
+ SMS_RECEPTION_INACTIVE = 0x02
+};
+
+enum sms_setting_type {
+ SMS_SETTING_TYPE_ROUTE = 0x02
+};
+
+enum sms_route_priority {
+ SMS_ROUTE_NOT_AVAILABLE = 0x00,
+ SMS_ROUTE_PRIORITY_1 = 0x01,
+ SMS_ROUTE_PRIORITY_2 = 0x02
+};
+
#ifdef __cplusplus
};
#endif
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 16/18] isimodem: sms updated with wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (14 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 11:43 ` [PATCH v2 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 18/18] isimodem: initial support for UICC phonebook Andreas Westin
17 siblings, 0 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 33787 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/sms.c | 958 +++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 822 insertions(+), 136 deletions(-)
diff --git a/drivers/isimodem/sms.c b/drivers/isimodem/sms.c
index 957b342..f721684 100644
--- a/drivers/isimodem/sms.c
+++ b/drivers/isimodem/sms.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
@@ -45,6 +46,7 @@
#include "isimodem.h"
#include "isiutil.h"
#include "sms.h"
+#include "uicc.h"
#include "debug.h"
/* This is a straightforward copy of the EF_smsp structure */
@@ -60,6 +62,18 @@ struct sim_efsmsp{
uint16_t alpha[17];
};
+/* USIM structure, 3GPP TS 31.102 */
+struct usim_efsmp {
+ uint8_t alphalen; /* not part of the USIM EF_smsp structure */
+ uint8_t alpha[241];
+ uint8_t indicators; /* parameter indicators */
+ uint8_t tp_dst[12];
+ uint8_t tp_sca[12];
+ uint8_t tp_pid; /* protocol identifier */
+ uint8_t tp_dcs; /* data coding scheme */
+ uint8_t tp_vp; /* validity period */
+};
+
/* Sub-block used by PN_SMS */
struct sms_params {
uint8_t location;
@@ -99,12 +113,52 @@ struct sms_common {
uint8_t *data;
};
+const unsigned char SMS_STATUS_REPORT = 0x02;
+
struct sms_data {
GIsiClient *client;
GIsiClient *sim;
- struct sim_efsmsp params;
+ GIsiVersion version;
+ struct sim_efsmsp sim_params;
+ struct usim_efsmp usim_params;
};
+static gboolean check_uicc_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",
+ uicc_message_id_name(g_isi_msg_id(msg)));
+ return FALSE;
+ }
+
+ if (!g_isi_msg_data_get_byte(msg, 0, &type))
+ return FALSE;
+
+ if (type != service) {
+ DBG("Unexpected service type: 0x%02X", type);
+ return FALSE;
+ }
+
+ if (!g_isi_msg_data_get_byte(msg, 1, &cause))
+ return FALSE;
+
+ if (cause != UICC_STATUS_OK) {
+ DBG("Request failed: %s", uicc_status_name(cause));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean check_sim_status(const GIsiMessage *msg, uint8_t msgid,
uint8_t service)
{
@@ -141,7 +195,8 @@ static gboolean check_sim_status(const GIsiMessage *msg, uint8_t msgid,
return TRUE;
}
-static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
+static gboolean check_sms_status_with_cause(const GIsiMessage *msg,
+ uint8_t msgid, uint8_t expected_cause, int cause_pos)
{
uint8_t cause;
@@ -156,12 +211,12 @@ static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
return FALSE;
}
- if (!g_isi_msg_data_get_byte(msg, 0, &cause)) {
+ if (!g_isi_msg_data_get_byte(msg, cause_pos, &cause)) {
DBG("Unable to parse cause");
return FALSE;
}
- if (cause == SMS_OK)
+ if (cause == expected_cause)
return TRUE;
if (cause == SMS_ERR_PP_RESERVED) {
@@ -178,6 +233,101 @@ static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
return FALSE;
}
+static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
+{
+ return check_sms_status_with_cause(msg, msgid, SMS_OK, 0);
+}
+
+static void sca_query_resp_uicc_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_sms *sms = cbd->user;
+ struct sms_data *sd = ofono_sms_get_data(sms);
+ ofono_sms_sca_query_cb_t cb = cbd->cb;
+
+ struct ofono_phone_number sca;
+ uint8_t bcd_len;
+ GIsiSubBlockIter iter;
+ int alphalen = 0;
+ uint32_t data_len = 0;
+ uint8_t sbcount = 0;
+
+ int i;
+ DBG("");
+
+ if (!check_uicc_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_READ_LINEAR_FIXED))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 5, &sbcount) || sbcount == 0)
+ goto error;
+
+ DBG("starting");
+ for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ if (g_isi_sb_iter_get_id(&iter) != UICC_SB_FILE_DATA)
+ continue;
+ DBG("found UICC_SB_FILE_DATA");
+ g_isi_sb_iter_get_dword(&iter, &data_len, 4);
+
+ DBG("got length %d", data_len);
+ if (data_len < 28)
+ goto error;
+
+ /*y is alpha identifier see 3GPP TS 31.102*/
+ alphalen = data_len - 28;
+
+ sd->usim_params.alphalen = alphalen;
+ for (i = 0; i < alphalen; i++) {
+ uint8_t t_byte;
+ g_isi_sb_iter_get_byte(&iter, &t_byte, 8 + i);
+ sd->usim_params.alpha[i] = t_byte;
+ }
+
+ g_isi_sb_iter_get_byte(&iter, &(sd->usim_params.indicators),
+ 8 + alphalen);
+
+ for (i = 0; i < 12; i++) {
+ uint8_t t_byte;
+ g_isi_sb_iter_get_byte(&iter, &t_byte,
+ 8 + alphalen + 1 + i);
+ sd->usim_params.tp_dst[i] = t_byte;
+ g_isi_sb_iter_get_byte(&iter, &t_byte,
+ 8 + alphalen + 1 + 12 + i);
+ sd->usim_params.tp_sca[i] = t_byte;
+ }
+ g_isi_sb_iter_get_byte(&iter, &(sd->usim_params.tp_pid),
+ alphalen + 1 + 12 + 12);
+ g_isi_sb_iter_get_byte(&iter, &(sd->usim_params.tp_dcs),
+ alphalen + 1 + 12 + 12 + 1);
+ g_isi_sb_iter_get_byte(&iter, &(sd->usim_params.tp_vp),
+ alphalen + 1 + 12 + 12 + 1 + 1);
+
+ DBG("indicators: %d", sd->usim_params.indicators & 0x2);
+ /*if TS-Service Centre Address absent*/
+ if (sd->usim_params.indicators & 0x2)
+ goto error;
+
+ bcd_len = sd->usim_params.tp_sca[0];
+
+ DBG("bcd length: %d", bcd_len);
+ if (bcd_len <= 1 || bcd_len > 12)
+ goto error;
+
+ extract_bcd_number(sd->usim_params.tp_sca + 2, bcd_len - 1,
+ sca.number);
+ sca.type = sd->usim_params.tp_sca[1];
+ DBG("new sca: %04X",
+ (unsigned int) strlen(sca.number));
+ CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
static void sca_query_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -203,16 +353,19 @@ static void sca_query_resp_cb(const GIsiMessage *msg, void *data)
info->alpha[info->alphalen - 1] = '\0';
- sd->params.absent = info->absent;
- sd->params.tp_pid = info->tp_pid;
- sd->params.tp_dcs = info->tp_dcs;
- sd->params.tp_vp = info->tp_vp;
+ sd->sim_params.absent = info->absent;
+ sd->sim_params.tp_pid = info->tp_pid;
+ sd->sim_params.tp_dcs = info->tp_dcs;
+ sd->sim_params.tp_vp = info->tp_vp;
- memcpy(sd->params.dst, info->dst, sizeof(sd->params.dst));
- memcpy(sd->params.sca, info->sca, sizeof(sd->params.sca));
+ memmove(sd->sim_params.dst, info->dst,
+ sizeof(sd->sim_params.dst));
+ memmove(sd->sim_params.sca, info->sca,
+ sizeof(sd->sim_params.sca));
- sd->params.alphalen = info->alphalen;
- memcpy(sd->params.alpha, info->alpha, sizeof(sd->params.alpha));
+ sd->sim_params.alphalen = info->alphalen;
+ memmove(sd->sim_params.alpha, info->alpha,
+ sizeof(sd->sim_params.alpha));
/*
* Bitmask indicating absence of parameters --
@@ -236,21 +389,86 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
+static gboolean sca_query_uicc(struct sms_data *sd, struct isi_cb_data *cbd)
+{
+ GIsiModem *modem = g_isi_client_modem(sd->sim);
+ int8_t app_id = get_app_id(modem);
+ uint8_t client_id = get_client_id(modem);
+ int app_type = get_app_type(modem);
+ DBG("");
+ if (app_id != -1 && client_id != 0) {
+ int mf_path = 0x3F00;
+ int df_path = (app_type == UICC_APPL_TYPE_UICC_USIM) ? 0x7FFF
+ : 0x7F10;
+ int df_len = 4;
+ uint8_t msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_READ_LINEAR_FIXED,
+ app_id,
+ UICC_SESSION_ID_NOT_USED,
+ 0, 0, /*fillers*/
+ 3, /*nro of sub blocks*/
+
+ UICC_SB_CLIENT >> 8, /*1st subblock*/
+ UICC_SB_CLIENT & 0xFF,
+ 0,/*subblock length*/
+ 8,/*subblock length*/
+ 0, 0, 0,/*fillers*/
+ client_id,
+
+ UICC_SB_APPL_PATH >> 8,/*2nd subblock*/
+ UICC_SB_APPL_PATH & 0xFF,
+ 0,/*subblock length*/
+ 16,/*subblock length*/
+ 0x6F42 >> 8,/*Elementary file ID for EFsmsp*/
+ 0x6F42 & 0xFF,
+ UICC_SFI_NOT_PRESENT,
+ 0,/*filler*/
+ df_len,/*Path length*/
+ 0,/*filler*/
+ mf_path >> 8,/*DF Path MF*/
+ mf_path & 0xFF,
+ df_path >> 8,/*DF Path DFtelecom*/
+ df_path & 0xFF,
+ 0, 0,/*fillers 0-3*/
+ UICC_SB_LINEAR_FIXED >> 8,/*3rd subblock*/
+ UICC_SB_LINEAR_FIXED & 0xFF,
+ 0,/*subblock length*/
+ 8,/*subblock length*/
+ 1,/*The record in the file*/
+ 0,/*offset 0 == beginning of the record*/
+ 0,/*data amount 0 == until end of record*/
+ 0,/*filler*/
+ };
+
+ return g_isi_client_send(sd->sim, msg, sizeof(msg),
+ sca_query_resp_uicc_cb, cbd, g_free);
+ }
+
+ return FALSE;
+}
+
static void isi_sca_query(struct ofono_sms *sms,
ofono_sms_sca_query_cb_t cb, void *data)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
-
- const uint8_t msg[] = {
+ uint8_t msg[] = {
SIM_SMS_REQ,
READ_PARAMETER,
1, /* Location, default is 1 */
};
+ DBG("");
- if (cbd == NULL || sd == NULL || sd->sim == NULL)
+ if (sd == NULL || sd->sim == NULL || cbd == NULL)
goto error;
+ if (PN_UICC == g_isi_client_resource(sd->sim)) {
+ if (!sca_query_uicc(sd, cbd))
+ goto error;
+ return;
+ }
+
if (g_isi_client_send(sd->sim, msg, sizeof(msg),
sca_query_resp_cb, cbd, g_free))
return;
@@ -260,6 +478,20 @@ error:
g_free(cbd);
}
+static void sca_set_resp_uicc_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sms_sca_set_cb_t cb = cbd->cb;
+
+ if (!check_uicc_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_UPDATE_LINEAR_FIXED)) {
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ return;
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+}
+
static void sca_set_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -273,6 +505,103 @@ static void sca_set_resp_cb(const GIsiMessage *msg, void *data)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
+static gboolean sca_uicc_set(struct sms_data *sd, struct isi_cb_data *cbd,
+ const struct ofono_phone_number *sca)
+{
+ GIsiModem *modem = g_isi_client_modem(sd->sim);
+ int8_t app_id = get_app_id(modem);
+ int8_t app_type = get_app_type(modem);
+ int8_t client_id = get_client_id(modem);
+ int mf_path = 0x3F00;
+ int df_path = (app_type == UICC_APPL_TYPE_UICC_USIM) ? 0x7FFF : 0x7F10;
+ int df_len = 4;
+ int sca_len = 1 + (strlen(sca->number) + 1) / 2;
+ size_t sb_file_data_length = 2 + 2 + 4 + sca_len + 1 + 1 + 12;
+ size_t fill_count = 4 - (sb_file_data_length % 4);
+ uint8_t bcd[sca_len + 12 + 1 + 1];
+ uint8_t *fill_data = g_try_malloc0(fill_count);
+ int i;
+
+ encode_bcd_number(sca->number, bcd + 15);
+ bcd[0] = sd->usim_params.indicators & 0xFD;
+
+ for (i = 0; i < 12; i++) {
+ if (sd->usim_params.tp_dst[0] == '\0')
+ bcd[i + 1] = 0xFF;
+ else
+ bcd[i + 1] = sd->usim_params.tp_dst[i];
+ }
+
+ bcd[13] = sca_len;
+ bcd[14] = sca->type;
+
+ if ((app_id != -1) && (client_id != -1)) {
+ uint8_t msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_UPDATE_LINEAR_FIXED,
+ app_id,
+ UICC_SESSION_ID_NOT_USED,
+ 0, 0, /*fillers*/
+ 4, /*nro of sub blocks*/
+ /*1*/
+ UICC_SB_CLIENT >> 8, /*1st subblock*/
+ UICC_SB_CLIENT & 0xFF,
+ 0,/*subblock length*/
+ 8,/*subblock length*/
+ 0, 0, 0,/*fillers*/
+ client_id,
+ /*2*/
+ UICC_SB_LINEAR_FIXED >> 8,/*3rd subblock*/
+ UICC_SB_LINEAR_FIXED & 0xFF,
+ 0,/*subblock length*/
+ 8,/*subblock length*/
+ 1,/*The record in the file*/
+ sd->usim_params.alphalen,
+ /* offset 0 == beginning of the record */
+ sca_len + 1 + 12 + 1, /* data amount 0
+ * == until end of
+ * record */
+ 0,/*filler*/
+ /*3*/
+ UICC_SB_APPL_PATH >> 8,/*2nd subblock*/
+ UICC_SB_APPL_PATH & 0xFF,
+ 0,/*subblock length*/
+ 16,/*subblock length*/
+ 0x6F42 >> 8,/*Elementary file ID for EFsmsp*/
+ 0x6F42 & 0xFF,
+ UICC_SFI_NOT_PRESENT,
+ 0,/*filler*/
+ df_len,/*Path length*/
+ 0,/*filler*/
+ mf_path >> 8,/*DF Path MF*/
+ mf_path & 0xFF,
+ df_path >> 8,/*DF Path DFtelecom*/
+ df_path & 0xFF,
+ 0, 0,/*fillers 0-3*/
+ /*4*/
+ UICC_SB_FILE_DATA >> 8,
+ UICC_SB_FILE_DATA & 0xFF,
+ (sb_file_data_length + fill_count) >> 8,
+ (sb_file_data_length + fill_count) & 0xFF,
+ (sca_len + 1 + 12 + 1) >> 24,
+ (sca_len + 1 + 12 + 1) >> 16,
+ (sca_len + 1 + 12 + 1) >> 8,
+ (sca_len + 1 + 12 + 1) & 0xFF,
+ };
+ struct iovec iov[3] = {
+ { msg, sizeof(msg) },
+ { bcd, sizeof(bcd) },
+ { fill_data, fill_count },
+ };
+
+ return g_isi_client_vsend(sd->sim, iov, G_N_ELEMENTS(iov),
+ sca_set_resp_uicc_cb, cbd, g_free);
+ }
+ g_free(fill_data);
+ return FALSE;
+
+}
+
static void isi_sca_set(struct ofono_sms *sms,
const struct ofono_phone_number *sca,
ofono_sms_sca_set_cb_t cb, void *data)
@@ -280,29 +609,34 @@ static void isi_sca_set(struct ofono_sms *sms,
struct sms_data *sd = ofono_sms_get_data(sms);
struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
uint8_t *bcd;
-
uint8_t msg[] = {
SIM_SMS_REQ,
UPDATE_PARAMETER,
1, /* Location, default is 1 */
};
-
- struct iovec iov[2] = {
+ struct iovec iov[] = {
{ msg, sizeof(msg) },
- { &sd->params, sizeof(sd->params) },
+ { &sd->sim_params, sizeof(sd->sim_params) },
};
if (cbd == NULL || sd == NULL)
goto error;
- bcd = sd->params.sca;
- sd->params.absent &= ~0x02;
+ if (PN_UICC == g_isi_client_resource(sd->sim)) {
+ if (!sca_uicc_set(sd, cbd, sca))
+ goto error;
+ return;
+ }
+
+ bcd = sd->sim_params.sca;
+ sd->sim_params.absent &= ~0x02;
encode_bcd_number(sca->number, bcd + 2);
bcd[0] = 1 + (strlen(sca->number) + 1) / 2;
bcd[1] = sca->type & 0xFF;
- if (g_isi_client_vsend(sd->sim, iov, 2, sca_set_resp_cb, cbd, g_free))
+ if (g_isi_client_vsend(sd->sim, iov, G_N_ELEMENTS(iov),
+ sca_set_resp_cb, cbd, g_free))
return;
error:
@@ -310,6 +644,32 @@ error:
g_free(cbd);
}
+static void submit_resp_v2_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sms_submit_cb_t cb = cbd->cb;
+ struct sms_report *report;
+ size_t len = sizeof(struct sms_report);
+ DBG("");
+
+ if (g_isi_msg_id(msg) != SMS_MESSAGE_SEND_RESP)
+ goto error;
+
+ if (len > g_isi_msg_data_len(msg))
+ goto error;
+
+ if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &report, len))
+ goto error;
+
+ if (report->type == SMS_CAUSE_TYPE_COMMON && report->cause == SMS_OK) {
+ CALLBACK_WITH_SUCCESS(cb, report->ref, cbd->data);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
static void submit_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -349,83 +709,244 @@ static void isi_submit(struct ofono_sms *sms, unsigned char *pdu,
struct sms_data *sd = ofono_sms_get_data(sms);
struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
- uint8_t use_sca = pdu_len - tpdu_len != 1 || pdu[0] == 0;
-
- uint8_t *tpdu = pdu + pdu_len - tpdu_len;
- uint8_t filler_len = (-tpdu_len) & 3;
- uint8_t tpdu_sb_len = 4 + tpdu_len + filler_len;
+ if (sd == NULL)
+ goto error;
- uint8_t sca_sb_len = use_sca ? 16 : 0;
+ if (sd->version.major == 9 && sd->version.minor >= 1) {
+
+ uint8_t sca_len = pdu_len - tpdu_len;
+ uint8_t *tpdu = pdu + sca_len;
+ uint8_t msg[] = {
+ SMS_MESSAGE_SEND_REQ,
+ mms, /* More messages to send*/
+ SMS_ROUTE_DEFAULT,
+ FALSE, /* Repeated message*/
+ 0, 0, /* fillers*/
+ 2, /* no of subblocks*/
+ SMS_GSM_TPDU_25 >> 8, /* first subblock*/
+ SMS_GSM_TPDU_25 & 0xFF,
+ (tpdu_len + 6) >> 8,
+ (tpdu_len + 6) & 0xFF,
+ tpdu_len,
+ 0x00,
+ /* databytes come here */
+ };
+ uint8_t parameters[] = {
+ SMS_GSM_PARAMETERS >> 8,
+ SMS_GSM_PARAMETERS & 0xFF,
+ 8 >> 8, /* subblock length*/
+ 8 & 0xFF,
+ /*
+ * location. We might have to fetch this by
+ * SMS_SETTINGS_READ_REQ
+ */
+ 1,/*SMS_DEFAULT_PARAMETER_LOCATION = 0 else
+ range 1-255*/
+ 0x02, /*SMS_PI_SERVICE_CENTRE_ADDRESS*/
+ 0, 0,
+ };
+ struct iovec iov[3] = {
+ { msg, sizeof(msg) },
+ { tpdu, tpdu_len },
+ { parameters, sizeof(parameters) },
+ };
+
+ if ((g_isi_client_vsend_with_timeout(sd->client, iov,
+ G_N_ELEMENTS(iov), SMS_TIMEOUT,
+ submit_resp_v2_cb, cbd, g_free)))
+ return;
+ } else {
+ uint8_t use_sca = pdu_len - tpdu_len != 1 || pdu[0] == 0;
+
+ uint8_t *tpdu = pdu + pdu_len - tpdu_len;
+ uint8_t filler_len = (-tpdu_len) & 3;
+ uint8_t tpdu_sb_len = 4 + tpdu_len + filler_len;
+
+ uint8_t sca_sb_len = use_sca ? 16 : 0;
+
+ uint8_t msg[] = {
+ SMS_MESSAGE_SEND_REQ,
+ mms,
+ SMS_ROUTE_CS_PREF,
+ 0, /* Is this a re-send? */
+ SMS_SENDER_ANY,
+ SMS_TYPE_TEXT_MESSAGE,
+ 1, /* Sub blocks */
+ SMS_GSM_TPDU,
+ 4 + tpdu_sb_len + sca_sb_len,
+ 0, /* Filler */
+ use_sca ? 2 : 1, /* Sub-sub blocks */
+ SMS_COMMON_DATA,
+ tpdu_sb_len,
+ tpdu_len,
+ 0, /* Packing required? */
+ /* TPDU */
+ };
+
+ static uint8_t filler[4];
+
+ uint8_t sca_sb[16] = {
+ SMS_ADDRESS,
+ 16,
+ SMS_GSM_0411_ADDRESS,
+ 0,
+ };
+
+ struct iovec iov[4] = {
+ { msg, sizeof(msg) },
+ { tpdu, tpdu_len },
+ { filler, filler_len },
+ { sca_sb, sca_sb_len },
+ };
+
+ if (cbd == NULL || sd == NULL)
+ goto error;
- uint8_t msg[] = {
- SMS_MESSAGE_SEND_REQ,
- mms,
- SMS_ROUTE_CS_PREF,
- 0, /* Is this a re-send? */
- SMS_SENDER_ANY,
- SMS_TYPE_TEXT_MESSAGE,
- 1, /* Sub blocks */
- SMS_GSM_TPDU,
- 4 + tpdu_sb_len + sca_sb_len,
- 0, /* Filler */
- use_sca ? 2 : 1, /* Sub-sub blocks */
- SMS_COMMON_DATA,
- tpdu_sb_len,
- tpdu_len,
- 0, /* Packing required? */
- /* TPDU */
- };
+ if (use_sca) {
+ sca_sb[3] = pdu_len - tpdu_len;
+ memmove(sca_sb + 4, pdu, sca_sb[3]);
+ }
- static uint8_t filler[4];
+ /*
+ * Modem seems to time out SMS_MESSAGE_SEND_REQ in 5 seconds.
+ * Wait normal timeout plus the modem timeout.
+ */
+ if (g_isi_client_vsend_with_timeout(sd->client, iov, 4,
+ SMS_TIMEOUT + 5,
+ submit_resp_cb, cbd, g_free))
+ return;
+ }
- uint8_t sca_sb[16] = {
- SMS_ADDRESS,
- 16,
- SMS_GSM_0411_ADDRESS,
- 0,
- };
+error:
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ g_free(cbd);
+}
- struct iovec iov[4] = {
- { msg, sizeof(msg) },
- { tpdu, tpdu_len },
- { filler, filler_len },
- { sca_sb, sca_sb_len },
- };
+static void bearer_query_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sms_bearer_query_cb_t cb = cbd->cb;
+ int bearer = 0;
+ uint8_t bear_high;
+ uint8_t bear_low;
- if (cbd == NULL || sd == NULL)
+ if (!check_sms_status(msg, SMS_SETTINGS_READ_RESP))
goto error;
- if (use_sca) {
- sca_sb[3] = pdu_len - tpdu_len;
- memcpy(sca_sb + 4, pdu, sca_sb[3]);
- }
+ g_isi_msg_data_get_byte(msg, 6, &bear_high);
+ g_isi_msg_data_get_byte(msg, 7, &bear_low);
- /*
- * Modem seems to time out SMS_MESSAGE_SEND_REQ in 5 seconds.
- * Wait normal timeout plus the modem timeout.
- */
- if (g_isi_client_vsend_with_timeout(sd->client, iov, 4,
- SMS_TIMEOUT + 5,
- submit_resp_cb, cbd, g_free))
+ /* check what bearer type was set */
+ if (bear_high == 0x00 && bear_low == 0x01)
+ bearer = 0;
+ else if (bear_high == 0x01 && bear_low == 0x00)
+ bearer = 1;
+ else if (bear_high == 0x02 && bear_low == 0x01)
+ bearer = 2;
+ else if (bear_high == 0x01 && bear_low == 0x02)
+ bearer = 3;
+
+ CALLBACK_WITH_SUCCESS(cb, bearer, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, bearer, cbd->data);
+}
+
+static void set_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sms_bearer_set_cb_t cb = cbd->cb;
+ struct sms_data *sd;
+ int cause_pos = 0;
+
+ if (cbd == NULL)
return;
+ sd = ofono_sms_get_data(cbd->user);
+
+ if (sd == NULL)
+ goto error;
+
+ if (sd->version.major == 9 && sd->version.minor >= 1)
+ cause_pos = 1;
+
+ if (!check_sms_status_with_cause(msg, SMS_SETTINGS_UPDATE_RESP, SMS_OK,
+ cause_pos))
+ goto error;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
error:
- CALLBACK_WITH_FAILURE(cb, -1, data);
- g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void isi_bearer_query(struct ofono_sms *sms,
ofono_sms_bearer_query_cb_t cb, void *data)
{
- DBG("Not implemented");
- CALLBACK_WITH_FAILURE(cb, -1, data);
+ struct sms_data *sd = ofono_sms_get_data(sms);
+ struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
+ unsigned char msg[] = {
+ SMS_SETTINGS_READ_REQ,
+ SMS_SETTING_TYPE_ROUTE,
+ 0
+ };
+
+ if (cbd && g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SMS_TIMEOUT, bearer_query_resp_cb, cbd, g_free))
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ g_free(cbd);
}
static void isi_bearer_set(struct ofono_sms *sms, int bearer,
ofono_sms_bearer_set_cb_t cb, void *data)
{
- DBG("Not implemented");
+ struct sms_data *sd = ofono_sms_get_data(sms);
+ struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
+ unsigned char bearer_type[2] = {SMS_ROUTE_NOT_AVAILABLE,
+ SMS_ROUTE_NOT_AVAILABLE
+ };
+
+ switch (bearer) {
+ case 0:
+ bearer_type[0] = SMS_ROUTE_NOT_AVAILABLE;
+ bearer_type[1] = SMS_ROUTE_PRIORITY_1;
+ break;
+ case 1:
+ bearer_type[0] = SMS_ROUTE_PRIORITY_1;
+ bearer_type[1] = SMS_ROUTE_NOT_AVAILABLE;
+ break;
+ case 2:
+ bearer_type[0] = SMS_ROUTE_PRIORITY_2;
+ bearer_type[1] = SMS_ROUTE_PRIORITY_1;
+ break;
+ case 3:
+ bearer_type[0] = SMS_ROUTE_PRIORITY_1;
+ bearer_type[1] = SMS_ROUTE_PRIORITY_2;
+ break;
+ }
+
+ if (cbd != NULL && sd != NULL) {
+ unsigned char msg[] = {
+ SMS_SETTINGS_UPDATE_REQ,
+ SMS_SETTING_TYPE_ROUTE,
+ 1, /* one subblock */
+ SMS_GSM_ROUTE_INFO >> 8,
+ SMS_GSM_ROUTE_INFO & 0xFF,
+ 8 >> 8,
+ 8 & 0xFF,
+ bearer_type[0], /* cs priority */
+ bearer_type[1], /* ps priority */
+ 0, 0
+ };
+
+ if (g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SMS_TIMEOUT, set_resp_cb, cbd, g_free))
+ return;
+ }
+
CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
}
static void send_status_ind_cb(const GIsiMessage *msg, void *data)
@@ -456,7 +977,8 @@ static void report_resp_cb(const GIsiMessage *msg, void *data)
if (g_isi_msg_error(msg) < 0)
return;
- if (g_isi_msg_id(msg) != SMS_GSM_RECEIVED_PP_REPORT_RESP)
+ if (g_isi_msg_id(msg) != SMS_GSM_RECEIVED_PP_REPORT_RESP &&
+ g_isi_msg_id(msg) != SMS_RECEIVED_MSG_REPORT_RESP)
return;
if (!g_isi_msg_data_get_byte(msg, 0, &cause))
@@ -465,27 +987,42 @@ static void report_resp_cb(const GIsiMessage *msg, void *data)
DBG("Report resp cause=0x%"PRIx8, cause);
}
-static gboolean send_deliver_report(GIsiClient *client, gboolean success)
+static gboolean send_deliver_report(struct sms_data *sd, gboolean success)
{
uint8_t cause_type = !success ? SMS_CAUSE_TYPE_GSM : 0;
uint8_t cause = !success ? SMS_GSM_ERR_MEMORY_CAPACITY_EXC : 0;
- uint8_t msg[] = {
- SMS_GSM_RECEIVED_PP_REPORT_REQ,
- cause_type, /* Cause type */
- cause, /* SMS cause */
- 0, 0, 0, /* Filler */
- 1, /* Sub blocks */
- SMS_GSM_DELIVER_REPORT,
- 8,
- 0, /* Message parameters */
- 0, /* Cause type */
- 0, 0, 0, /* Filler */
- 0, /* Sub blocks */
- };
- size_t len = sizeof(msg);
+ if (sd == NULL)
+ return FALSE;
- return g_isi_client_send(client, msg, len, report_resp_cb, NULL, NULL);
+ if (sd->version.major == 9 && sd->version.minor >= 1) {
+ uint8_t msg[] = {
+ SMS_RECEIVED_MSG_REPORT_REQ,
+ cause_type,
+ cause,
+ 0, 0, 0, /* Filler */
+ 0, /* nro of subblocks*/
+ };
+ return g_isi_client_send(sd->client, msg, sizeof(msg),
+ report_resp_cb, NULL, NULL);
+ } else {
+ uint8_t msg[] = {
+ SMS_GSM_RECEIVED_PP_REPORT_REQ,
+ cause_type, /* Cause type */
+ cause, /* SMS cause */
+ 0, 0, 0, /* Filler */
+ 1, /* Sub blocks */
+ SMS_GSM_DELIVER_REPORT,
+ 8,
+ 0, /* Message parameters */
+ 0, /* Cause type */
+ 0, 0, 0, /* Filler */
+ 0, /* Sub blocks */
+ };
+
+ return g_isi_client_send(sd->client, msg, sizeof(msg),
+ report_resp_cb, NULL, NULL);
+ }
}
static gboolean parse_sms_address(GIsiSubBlockIter *iter, struct sms_addr *add)
@@ -583,8 +1120,8 @@ static void routing_ntf_cb(const GIsiMessage *msg, void *data)
tpdu.len + addr.len > sizeof(pdu))
return;
- memcpy(pdu, addr.data, addr.len);
- memcpy(pdu + addr.len, tpdu.data, tpdu.len);
+ memmove(pdu, addr.data, addr.len);
+ memmove(pdu + addr.len, tpdu.data, tpdu.len);
ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
@@ -594,19 +1131,101 @@ static void routing_ntf_cb(const GIsiMessage *msg, void *data)
* no such indication from core, so we just blindly trust that
* it did The Right Thing here.
*/
- send_deliver_report(sd->client, TRUE);
+ send_deliver_report(sd, TRUE);
}
-static void routing_resp_cb(const GIsiMessage *msg, void *data)
+static void received_msg_ind_cb(const GIsiMessage *msg, void *data)
{
struct ofono_sms *sms = data;
struct sms_data *sd = ofono_sms_get_data(sms);
- if (!check_sms_status(msg, SMS_PP_ROUTING_RESP))
+ GIsiSubBlockIter iter;
+ uint8_t *sca = NULL;
+ uint8_t sca_len = 0;
+ uint8_t *tpdu = NULL;
+ uint8_t tpdu_len = 0;
+ unsigned char pdu[176];
+ unsigned char type;
+ uint8_t sbcount;
+ DBG("");
+
+ if (!check_sms_status(msg, SMS_RECEIVED_MSG_IND))
return;
- g_isi_client_ntf_subscribe(sd->client, SMS_PP_ROUTING_NTF,
- routing_ntf_cb, sms);
+ g_isi_msg_data_get_byte(msg, 1, &sbcount);
+
+ for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, sbcount);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ uint8_t type;
+ void *data;
+ uint8_t data_len;
+ case SMS_ADDRESS:
+ if (!g_isi_sb_iter_get_byte(&iter, &type, 4)
+ || !g_isi_sb_iter_get_byte(&iter,
+ &data_len, 5)
+ || !g_isi_sb_iter_get_data(&iter,
+ &data, 6)
+ || type != SMS_SMSC_ADDRESS)
+ break;
+
+ sca = data;
+ sca_len = data_len;
+ break;
+ case SMS_GSM_TPDU_25:
+ if (!g_isi_sb_iter_get_byte(&iter, &data_len, 4)
+ || !g_isi_sb_iter_get_data(&iter,
+ &data, 6))
+ break;
+ tpdu = data;
+ tpdu_len = data_len;
+ break;
+ }
+ }
+
+ if (tpdu == NULL || sca == NULL || tpdu_len + sca_len > sizeof(pdu))
+ return;
+
+ memmove(pdu, sca, sca_len);
+ memmove(pdu + sca_len, tpdu, tpdu_len);
+ /* 23.040 9.2.3.1 */
+ type = tpdu[0] & 0x03;
+
+ if (type == SMS_STATUS_REPORT) {
+ ofono_sms_status_notify(sms,
+ pdu, tpdu_len + sca_len, tpdu_len);
+ } else {
+ ofono_sms_deliver_notify(sms,
+ pdu, tpdu_len + sca_len, tpdu_len);
+ }
+
+ send_deliver_report(sd, TRUE);
+}
+
+static void receive_msg_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sms *sms = data;
+
+ if (sms == NULL)
+ return;
+
+ if (!check_sms_status_with_cause(msg, SMS_RECEIVE_MESSAGE_RESP,
+ SMS_RECEPTION_ACTIVE, 0))
+ return;
+
+ ofono_sms_register(sms);
+}
+
+static void routing_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sms *sms = data;
+
+ if (sms == NULL)
+ return;
+
+ if (!check_sms_status(msg, SMS_PP_ROUTING_RESP))
+ return;
ofono_sms_register(sms);
}
@@ -616,28 +1235,36 @@ static void sim_reachable_cb(const GIsiMessage *msg, void *data)
struct ofono_sms *sms = data;
struct sms_data *sd = ofono_sms_get_data(sms);
- const uint8_t req[] = {
- SMS_PP_ROUTING_REQ,
- SMS_ROUTING_SET,
- 0x01, /* Sub-block count */
- SMS_GSM_ROUTING,
- 0x08, /* Sub-block length */
- SMS_GSM_TPDU_ROUTING,
- SMS_GSM_MT_ALL_TYPE,
- 0x00, 0x00, 0x00, /* Filler */
- 0x00 /* Sub-sub-block count */
- };
- size_t len = sizeof(req);
+ if (sd == NULL)
+ return;
if (g_isi_msg_error(msg) < 0) {
DBG("unable to find SIM resource");
g_isi_client_destroy(sd->sim);
sd->sim = NULL;
}
+}
- g_isi_client_ind_subscribe(sd->client, SMS_MESSAGE_SEND_STATUS_IND,
- send_status_ind_cb, sms);
- g_isi_client_send(sd->client, req, len, routing_resp_cb, sms, NULL);
+static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sms *sms = data;
+ struct sms_data *sd = ofono_sms_get_data(sms);
+
+ if (sd == NULL)
+ return;
+
+ if (g_isi_msg_error(msg) < 0) {
+ GIsiModem *modem = g_isi_client_modem(sd->sim);
+ g_isi_client_destroy(sd->sim);
+ sd->sim = g_isi_client_create(modem, PN_SMS);
+
+ if (sd->sim == NULL)
+ return;
+
+ g_isi_client_set_timeout(sd->sim, SIM_TIMEOUT);
+ g_isi_client_verify(sd->sim, sim_reachable_cb, sms, NULL);
+ return;
+ }
}
static void sms_reachable_cb(const GIsiMessage *msg, void *data)
@@ -650,9 +1277,41 @@ static void sms_reachable_cb(const GIsiMessage *msg, void *data)
return;
}
+ if (sd == NULL)
+ return;
+
ISI_VERSION_DBG(msg);
+ sd->version.major = g_isi_msg_version_major(msg);
+ sd->version.minor = g_isi_msg_version_minor(msg);
+
+ if (sd->version.major == 9 && sd->version.minor >= 1) {
+ uint8_t req[] = {
+ SMS_RECEIVE_MESSAGE_REQ,
+ SMS_RECEPTION_ACTIVATE,
+ 0,
+ };
+ size_t len = sizeof(req);
+ g_isi_client_send(sd->client, req, len,
+ receive_msg_resp_cb, sms, NULL);
+
+ } else {
+ uint8_t req[] = {
+ SMS_PP_ROUTING_REQ,
+ SMS_ROUTING_SET,
+ 0x01, /* Sub-block count */
+ SMS_GSM_ROUTING,
+ 0x08, /* Sub-block length */
+ SMS_GSM_TPDU_ROUTING,
+ SMS_GSM_MT_ALL_TYPE,
+ 0x00, 0x00, 0x00, /* Filler */
+ 0x00 /* Sub-sub-block count */
+ };
+ size_t len = sizeof(req);
+ g_isi_client_send(sd->client, req, len,
+ routing_resp_cb, sms, NULL);
+ }
- g_isi_client_verify(sd->sim, sim_reachable_cb, sms, NULL);
+ g_isi_client_verify(sd->sim, uicc_reachable_cb, sms, NULL);
}
static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
@@ -664,28 +1323,44 @@ static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
if (sd == NULL)
return -ENOMEM;
- sd->params.absent = 0xFF;
- sd->params.alphalen = 1; /* Includes final UCS2-coded NUL */
+ sd->sim_params.absent = 0xFF;
+ sd->sim_params.alphalen = 1; /* Includes final UCS2-coded NUL */
+
+ sd->usim_params.indicators = 0xFF;
+ sd->usim_params.alphalen = 0; /* Includes final UCS2-coded NUL */
+
sd->client = g_isi_client_create(modem, PN_SMS);
if (sd->client == NULL)
goto nomem;
- sd->sim = g_isi_client_create(modem, PN_SIM);
+ sd->sim = g_isi_client_create(modem, PN_UICC);
+
if (sd->sim == NULL)
goto nomem;
- g_isi_client_set_timeout(sd->client, SMS_TIMEOUT);
- g_isi_client_set_timeout(sd->sim, SIM_TIMEOUT);
ofono_sms_set_data(sms, sd);
+ g_isi_client_ind_subscribe(sd->client, SMS_MESSAGE_SEND_STATUS_IND,
+ send_status_ind_cb, sms);
+
+ g_isi_client_ind_subscribe(sd->client, SMS_RECEIVED_MSG_IND,
+ received_msg_ind_cb, sms);
+
+ g_isi_client_ntf_subscribe(sd->client, SMS_PP_ROUTING_NTF,
+ routing_ntf_cb, sms);
+
g_isi_client_verify(sd->client, sms_reachable_cb, sms, NULL);
+ g_isi_client_set_timeout(sd->client, SMS_TIMEOUT);
+ g_isi_client_set_timeout(sd->sim, SIM_TIMEOUT);
+
return 0;
nomem:
g_isi_client_destroy(sd->client);
+ g_isi_client_destroy(sd->sim);
g_free(sd);
return -ENOMEM;
}
@@ -694,28 +1369,39 @@ static void isi_sms_remove(struct ofono_sms *sms)
{
struct sms_data *sd = ofono_sms_get_data(sms);
- const uint8_t msg[] = {
- SMS_PP_ROUTING_REQ,
- SMS_ROUTING_RELEASE,
- 0x01, /* Sub-block count */
- SMS_GSM_ROUTING,
- 0x08, /* Sub-block length */
- SMS_GSM_TPDU_ROUTING,
- SMS_GSM_MT_ALL_TYPE,
- 0x00, 0x00, 0x00, /* Filler */
- 0x00 /* Sub-sub-block count */
- };
-
- ofono_sms_set_data(sms, NULL);
-
if (sd == NULL)
return;
+ ofono_sms_set_data(sms, NULL);
+
/*
* Send a promiscuous routing release, so as not to
* hog resources unnecessarily after being removed
*/
- g_isi_client_send(sd->client, msg, sizeof(msg), NULL, NULL, NULL);
+ if (sd->version.major == 9 && sd->version.minor >= 1) {
+ uint8_t msg[] = {
+ SMS_RECEIVE_MESSAGE_REQ,
+ SMS_RECEPTION_DEACTIVATE,
+ 0x0,
+ };
+ g_isi_client_send(sd->client, msg, sizeof(msg),
+ NULL, NULL, NULL);
+ } else {
+ uint8_t msg[] = {
+ SMS_PP_ROUTING_REQ,
+ SMS_ROUTING_RELEASE,
+ 0x01, /* Sub-block count */
+ SMS_GSM_ROUTING,
+ 0x08, /* Sub-block length */
+ SMS_GSM_TPDU_ROUTING,
+ SMS_GSM_MT_ALL_TYPE,
+ 0x00, 0x00, 0x00, /* Filler */
+ 0x00 /* Sub-sub-block count */
+ };
+ g_isi_client_send(sd->client, msg, sizeof(msg),
+ NULL, NULL, NULL);
+ }
+
g_isi_client_destroy(sd->client);
g_isi_client_destroy(sd->sim);
g_free(sd);
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 17/18] isimodem: CBS for wgmodem2.5
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (15 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
2011-02-23 11:43 ` [PATCH v2 18/18] isimodem: initial support for UICC phonebook Andreas Westin
17 siblings, 0 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 14595 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/cbs.c | 414 +++++++++++++++++++++++++++++++++++++++++-----
drivers/isimodem/debug.c | 4 +
drivers/isimodem/sms.h | 7 +-
3 files changed, 383 insertions(+), 42 deletions(-)
diff --git a/drivers/isimodem/cbs.c b/drivers/isimodem/cbs.c
index b969c1f..67274be 100644
--- a/drivers/isimodem/cbs.c
+++ b/drivers/isimodem/cbs.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
@@ -47,12 +48,16 @@
struct cbs_data {
GIsiClient *client;
+ uint8_t subscription_nr;
+ GIsiVersion version;
};
struct cbs_info {
uint8_t pdu[88];
};
+GIsiClient *pn_sms_client;
+
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
{
uint8_t cause;
@@ -89,18 +94,292 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
return FALSE;
}
+static void reset_buf(char *buf, char *buf_2, int buf_len)
+{
+ memset(buf, '\0', buf_len);
+ memset(buf_2, '\0', buf_len);
+}
+
+static int get_topics_len(const char *topics)
+{
+ int i = 0;
+ int k = 0;
+ int length = 0;
+ char buf[6];
+ char buf_2[6];
+
+ reset_buf(buf, buf_2, 6);
+
+ while (*topics != '\0') {
+ if (*topics == ',') {
+ reset_buf(buf, buf_2, 6);
+ k = 0;
+ length++;
+ } else if (*topics != ',' && *topics != '-') {
+ buf[k] = *topics;
+ k++;
+ } else if (*topics == '-') {
+ topics++;
+ i++;
+ k = 0;
+
+ while (*topics != ',' && *topics != '\0') {
+ buf_2[k] = *topics;
+ topics++;
+ i++;
+ k++;
+ }
+
+ length = length + atoi(buf_2) - atoi(buf) + 1;
+ k = 0;
+ }
+ if (*topics != '\0') {
+ topics++;
+ i++;
+ }
+ }
+
+ topics = topics - i;
+ return length;
+}
+
+static void parse_topics(const char *topics, gint16 *topics_parsed)
+{
+ int j = 0;
+ int k = 0;
+ char buf[6];
+ char buf_2[6];
+
+ reset_buf(buf, buf_2, 6);
+
+ while (*topics != '\0') {
+ if (*topics != ',' && *topics != '-') {
+ buf[j] = *topics;
+ j++;
+ } else if (*topics == '-') {
+ topics++;
+ j = 0;
+
+ while (*topics != ',' && *topics != '\0') {
+ buf_2[j] = *topics;
+ topics++;
+ j++;
+ }
+
+ for (j = 0; j <= (atoi(buf_2) - atoi(buf)); j++) {
+ topics_parsed[k] = atoi(buf) + j;
+ topics_parsed[k] = g_ntohs(topics_parsed[k]);
+ k++;
+ }
+
+ j = 0;
+ } else if (*topics == ',') {
+ topics_parsed[k] = atoi(buf);
+ topics_parsed[k] = g_ntohs(topics_parsed[k]);
+ reset_buf(buf, buf_2, 6);
+ j = 0;
+ k++;
+ }
+ if (*topics != '\0')
+ topics++;
+ }
+}
+
+static void set_topics_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct cbs_data *cd = ofono_cbs_get_data(cbd->user);
+ ofono_cbs_set_cb_t cb = cbd->cb;
+ uint8_t result;
+ DBG("");
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+ return;
+ }
+
+ if (g_isi_msg_data_len(msg) < 2 || g_isi_msg_id(msg) !=
+ SMS_CB_ROUTING_RESP)
+ goto error;
+
+ g_isi_msg_data_get_byte(msg, 1, &result);
+
+ if (result != SMS_OK)
+ goto error;
+
+ g_isi_msg_data_get_byte(msg, 0, &cd->subscription_nr);
+
+ DBG("got subscription nr: %d", cd->subscription_nr);
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
static void isi_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *data)
{
- DBG("Not implemented (topics=%s), all topics accepted", topics);
- CALLBACK_WITH_SUCCESS(cb, data);
+ struct cbs_data *cd = ofono_cbs_get_data(cbs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cbs, cb, data);
+ int topics_len = get_topics_len(topics);
+ gint16 topics_out[topics_len];
+
+ uint8_t msg[] = {
+ SMS_CB_ROUTING_REQ,
+ SMS_ROUTING_SET,
+ cd->subscription_nr,
+ 0x00, /*Subscription type*/
+ 0x00, /*Fillers*/
+ 0x00,
+ 0x01, /*Number of subblocks*/
+ 0x00,
+ 0x26, /*Subblock*/
+ 0x00,
+ topics_len * 2 + 6, /*Subblock length*/
+ 0x00,
+ topics_len, /*Number of topics*/
+ };
+ struct iovec iov[2] = {
+ { msg, sizeof(msg) },
+ { topics_out, sizeof(topics_out) },
+ };
+
+ if (cbd == NULL)
+ return;
+
+ if (cd == NULL)
+ goto error;
+
+ if (cd->version.major == 9 && cd->version.minor >= 1) {
+ parse_topics(topics, topics_out);
+
+ if (g_isi_client_vsend_with_timeout(cd->client, iov, 2,
+ CBS_TIMEOUT, set_topics_resp_cb, cbd, g_free))
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, data);
+ } else {
+ /*
+ * TODO: This should probably be put first in
+ * the function to avoid unecessary initialization
+ * and allocation. Fix when the version handling
+ * issue has been solved.
+ */
+ DBG("Not implemented (topics=%s), all topics accepted", topics);
+ CALLBACK_WITH_SUCCESS(cb, data);
+ }
+
+error:
+ g_free(cbd);
+}
+
+static void clear_topics_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct cbs_data *cd = ofono_cbs_get_data(cbd->user);
+ ofono_cbs_set_cb_t cb = cbd->cb;
+ DBG("");
+
+ if (!check_response_status(msg, SMS_CB_ROUTING_RESP))
+ goto error;
+
+ cd->subscription_nr = 0;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void isi_clear_topics(struct ofono_cbs *cbs,
ofono_cbs_set_cb_t cb, void *data)
{
- DBG("Not implemented");
- CALLBACK_WITH_SUCCESS(cb, data);
+ struct cbs_data *cd = ofono_cbs_get_data(cbs);
+ struct isi_cb_data *cbd = isi_cb_data_new(cbs, cb, data);
+
+ uint8_t msg[] = {
+ SMS_CB_ROUTING_REQ,
+ SMS_ROUTING_RELEASE,
+ cd->subscription_nr, /* Subscription number */
+ 0x00, /* Subscription type */
+ 0x00, /* Fillers */
+ 0x00,
+ 0x00 /*No subblocks*/
+ };
+
+ if (cbd == NULL)
+ return;
+
+ if (cd == NULL)
+ goto error;
+
+ if (cd->version.major == 9 && cd->version.minor >= 1) {
+ if (g_isi_client_send_with_timeout(cd->client, msg, sizeof(msg),
+ CBS_TIMEOUT, clear_topics_resp_cb,
+ cbd, g_free))
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, data);
+ } else {
+ /*
+ * TODO: This should probably be put first in
+ * the function to avoid unecessary initialization
+ * and allocation. Fix when the version handling
+ * issue has been solved.
+ */
+ DBG("Not implemented");
+ CALLBACK_WITH_SUCCESS(cb, data);
+ }
+error:
+ g_free(cbd);
+}
+
+static void routing_ind_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_cbs *cbs = data;
+ struct cbs_data *cd = ofono_cbs_get_data(cbs);
+ struct cbs_info info;
+ size_t len = sizeof(struct cbs_info);
+ GIsiSubBlockIter iter;
+ size_t subblock_len;
+ uint8_t sbcount;
+ uint8_t *pdu_data;
+
+ DBG("");
+
+ if (cd == NULL || !check_response_status(msg, SMS_CB_ROUTING_IND))
+ return;
+
+ g_isi_msg_data_get_byte(msg, 1, &sbcount);
+
+ for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, sbcount);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != SMS_GSM_CB_MESSAGE)
+ continue;
+
+ subblock_len = g_isi_sb_iter_get_len(&iter) - 4;
+
+ if (subblock_len > len &&
+ g_isi_sb_iter_get_data(&iter, (void **)&pdu_data, 4)) {
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (i < 6) /*account for filler in pos 6*/
+ info.pdu[i] = pdu_data[i];
+ else
+ info.pdu[i] = pdu_data[i+1];
+ }
+
+ DBG("CBS Message received");
+ ofono_cbs_notify(cbs, info.pdu, len);
+ return;
+ } else {
+ DBG("Error reading CBS message");
+ return;
+ }
+ }
}
static void routing_ntf_cb(const GIsiMessage *msg, void *data)
@@ -131,40 +410,70 @@ static void routing_ntf_cb(const GIsiMessage *msg, void *data)
static void routing_resp_cb(const GIsiMessage *msg, void *data)
{
struct ofono_cbs *cbs = data;
+
+ ofono_cbs_register(cbs);
+}
+
+static void reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_cbs *cbs = data;
struct cbs_data *cd = ofono_cbs_get_data(cbs);
+ uint8_t *new_msg;
- if (cd == NULL || !check_response_status(msg, SMS_GSM_CB_ROUTING_RESP))
+ if (cd == NULL)
return;
- g_isi_client_ntf_subscribe(cd->client, SMS_GSM_CB_ROUTING_NTF,
- routing_ntf_cb, cbs);
+ ISI_VERSION_DBG(msg);
+
+ cd->version.major = g_isi_msg_version_major(msg);
+ cd->version.minor = g_isi_msg_version_minor(msg);
+
+ if (cd->version.major == 9 && cd->version.minor >= 1) {
+ uint8_t t_msg[] = {
+ SMS_CB_ROUTING_REQ,
+ SMS_ROUTING_QUERY_ALL,
+ 0x00, /* New subscription*/
+ 0x00, /* Subscription type */
+ 0x00, /* Fillers */
+ 0x00,
+ 0x00 /* No subblocks*/
+ };
+ new_msg = g_try_malloc0(sizeof(t_msg));
+ memmove(new_msg, t_msg, sizeof(t_msg));
+ } else {
+ uint8_t t_msg[] = {
+ SMS_GSM_CB_ROUTING_REQ,
+ SMS_ROUTING_SET,
+ SMS_GSM_ROUTING_MODE_ALL,
+ SMS_CB_NOT_ALLOWED_IDS_LIST,
+ 0x00, /* Subject count */
+ 0x00, /* Language count */
+ 0x00, /* CB range */
+ 0x00, /* Subject list MSBS */
+ 0x00, /* Subject list LSBS */
+ 0x00 /* Languages */
+ };
+ new_msg = g_try_malloc0(sizeof(t_msg));
+ memmove(new_msg, t_msg, sizeof(t_msg));
+ }
- ofono_cbs_register(cbs);
+ g_isi_client_send(cd->client, new_msg, sizeof(msg),
+ routing_resp_cb, cbs, NULL);
+
+ g_free(new_msg);
}
static int isi_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
void *user)
{
GIsiModem *modem = user;
- struct cbs_data *cd;
-
- const uint8_t msg[] = {
- SMS_GSM_CB_ROUTING_REQ,
- SMS_ROUTING_SET,
- SMS_GSM_ROUTING_MODE_ALL,
- SMS_CB_NOT_ALLOWED_IDS_LIST,
- 0x00, /* Subject count */
- 0x00, /* Language count */
- 0x00, /* CB range */
- 0x00, /* Subject list MSBS */
- 0x00, /* Subject list LSBS */
- 0x00 /* Languages */
- };
+ struct cbs_data *cd = g_try_new0(struct cbs_data, 1);
- cd = g_try_new0(struct cbs_data, 1);
if (cd == NULL)
return -ENOMEM;
+ cd->subscription_nr = 0;
+
cd->client = g_isi_client_create(modem, PN_SMS);
if (cd->client == NULL) {
g_free(cd);
@@ -173,34 +482,56 @@ static int isi_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
ofono_cbs_set_data(cbs, cd);
- if (g_isi_client_send(cd->client, msg, sizeof(msg),
- routing_resp_cb, cbs, NULL))
- return 0;
+ g_isi_client_ind_subscribe(cd->client, SMS_CB_ROUTING_IND,
+ routing_ind_cb, cbs);
+
+ g_isi_client_ntf_subscribe(cd->client, SMS_GSM_CB_ROUTING_NTF,
+ routing_ntf_cb, cbs);
- return -errno;
+ g_isi_client_verify(cd->client, reachable_cb, cbs, NULL);
+
+ return 0;
}
static void isi_cbs_remove(struct ofono_cbs *cbs)
{
struct cbs_data *cd = ofono_cbs_get_data(cbs);
- const uint8_t msg[] = {
- SMS_GSM_CB_ROUTING_REQ,
- SMS_ROUTING_RELEASE,
- SMS_GSM_ROUTING_MODE_ALL,
- SMS_CB_NOT_ALLOWED_IDS_LIST,
- 0x00, /* Subject count */
- 0x00, /* Language count */
- 0x00, /* CB range */
- 0x00, /* Subject list MSBS */
- 0x00, /* Subject list LSBS */
- 0x00 /* Languages */
- };
-
- ofono_cbs_set_data(cbs, NULL);
+ uint8_t *msg;
if (cd == NULL)
return;
+ if (cd->version.major == 9 && cd->version.minor >= 1) {
+ uint8_t t_msg[] = {
+ SMS_CB_ROUTING_REQ,
+ SMS_ROUTING_RELEASE,
+ cd->subscription_nr, /* Subscription number */
+ 0x00, /* Subscription type */
+ 0x00, /* Fillers */
+ 0x00,
+ 0x00 /* No subblocks*/
+ };
+ msg = g_try_malloc0(sizeof(t_msg));
+ memmove(msg, t_msg, sizeof(t_msg));
+ } else {
+ uint8_t t_msg[] = {
+ SMS_GSM_CB_ROUTING_REQ,
+ SMS_ROUTING_RELEASE,
+ SMS_GSM_ROUTING_MODE_ALL,
+ SMS_CB_NOT_ALLOWED_IDS_LIST,
+ 0x00, /* Subject count */
+ 0x00, /* Language count */
+ 0x00, /* CB range */
+ 0x00, /* Subject list MSBS */
+ 0x00, /* Subject list LSBS */
+ 0x00 /* Languages */
+ };
+ msg = g_try_malloc0(sizeof(t_msg));
+ memmove(msg, t_msg, sizeof(t_msg));
+ }
+ ofono_cbs_set_data(cbs, NULL);
+
+
/*
* Send a promiscuous routing release, so as not to hog
* resources unnecessarily after being removed.
@@ -209,6 +540,7 @@ static void isi_cbs_remove(struct ofono_cbs *cbs)
g_isi_client_destroy(cd->client);
g_free(cd);
+ g_free(msg);
}
static struct ofono_cbs_driver driver = {
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index 1fd2226..ec3f3b3 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -449,6 +449,9 @@ const char *sms_message_id_name(enum sms_message_id value)
_(SMS_SETTINGS_UPDATE_RESP);
_(SMS_SETTINGS_READ_REQ);
_(SMS_SETTINGS_READ_RESP);
+ _(SMS_CB_ROUTING_REQ);
+ _(SMS_CB_ROUTING_RESP);
+ _(SMS_CB_ROUTING_IND);
_(SMS_RECEIVED_MSG_REPORT_REQ);
_(SMS_RECEIVED_MSG_REPORT_RESP);
_(SMS_RECEIVE_MESSAGE_REQ);
@@ -473,6 +476,7 @@ const char *sms_subblock_name(enum sms_subblock value)
_(SMS_GSM_TPDU);
_(SMS_GSM_TPDU_25);
_(SMS_GSM_ROUTE_INFO);
+ _(SMS_GSM_CBS_SUBSCRIPTION);
_(SMS_GSM_PARAMETERS);
_(SMS_COMMON_DATA);
_(SMS_ADDRESS);
diff --git a/drivers/isimodem/sms.h b/drivers/isimodem/sms.h
index a51adf2..03db354 100644
--- a/drivers/isimodem/sms.h
+++ b/drivers/isimodem/sms.h
@@ -130,6 +130,9 @@ enum sms_message_id {
SMS_SETTINGS_UPDATE_RESP = 0x31,
SMS_SETTINGS_READ_REQ = 0x32,
SMS_SETTINGS_READ_RESP = 0x33,
+ SMS_CB_ROUTING_REQ = 0x34,
+ SMS_CB_ROUTING_RESP = 0x35,
+ SMS_CB_ROUTING_IND = 0x36,
SMS_RECEIVED_MSG_REPORT_REQ = 0x3B,
SMS_RECEIVED_MSG_REPORT_RESP = 0x3C,
SMS_RECEIVE_MESSAGE_REQ = 0x41,
@@ -150,6 +153,7 @@ enum sms_subblock {
SMS_GSM_TPDU = 0x11,
SMS_GSM_TPDU_25 = 0x001C,
SMS_GSM_ROUTE_INFO = 0x0023,
+ SMS_GSM_CBS_SUBSCRIPTION = 0x002D,
SMS_GSM_PARAMETERS = 0x0031,
SMS_COMMON_DATA = 0x80,
SMS_ADDRESS = 0x82,
@@ -160,7 +164,8 @@ enum sms_routing_command {
SMS_ROUTING_SET = 0x01,
SMS_ROUTING_SUSPEND = 0x02,
SMS_ROUTING_RESUME = 0x03,
- SMS_ROUTING_UPDATE = 0x04
+ SMS_ROUTING_UPDATE = 0x04,
+ SMS_ROUTING_QUERY_ALL = 0x06
};
enum sms_route_preference {
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 18/18] isimodem: initial support for UICC phonebook
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
` (16 preceding siblings ...)
2011-02-23 11:43 ` [PATCH v2 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
@ 2011-02-23 11:43 ` Andreas Westin
17 siblings, 0 replies; 32+ messages in thread
From: Andreas Westin @ 2011-02-23 11:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 34290 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/phonebook.c | 1273 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 1243 insertions(+), 30 deletions(-)
diff --git a/drivers/isimodem/phonebook.c b/drivers/isimodem/phonebook.c
index 1f92d37..6b136b0 100644
--- a/drivers/isimodem/phonebook.c
+++ b/drivers/isimodem/phonebook.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
@@ -36,16 +37,40 @@
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/phonebook.h>
+#include <ofono/sim.h>
#include "util.h"
#include "isimodem.h"
#include "isiutil.h"
#include "sim.h"
+#include "simutil.h"
#include "debug.h"
+#include "uicc.h"
-struct pb_data {
- GIsiClient *client;
-};
+/* 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 UNUSED 0xFF
+
+#define EXT1_CP_SUBADDRESS 1
+#define EXT1_ADDITIONAL_DATA 2
+
+#define NAME_SIZE 64
+#define NUMBER_SIZE 256
+#define EMAIL_SIZE 128
+#define EXT_NUMBER_SIZE 24
+#define SNE_SIZE 64
+
+/* TON (Type Of Number) See TS 24.008 */
+#define TON_MASK 0x70
+#define TON_INTERNATIONAL 0x10
struct read_resp {
uint8_t service_type;
@@ -53,6 +78,81 @@ struct read_resp {
uint8_t data[];
};
+enum constructed_tag {
+ TYPE_1_TAG = 0xA8,
+ TYPE_2_TAG = 0xA9,
+ TYPE_3_TAG = 0xAA
+};
+
+enum file_type_tag {
+ TYPE_ADN = 0xC0,
+ TYPE_IAD = 0xC1,
+ TYPE_EXT1 = 0xC2,
+ TYPE_SNE = 0xC3,
+ TYPE_ANR = 0xC4,
+ TYPE_PBC = 0xC5,
+ TYPE_GPR = 0xC6,
+ TYPE_AAS = 0xC7,
+ TYPE_GAS = 0xC8,
+ TYPE_UID = 0xC9,
+ TYPE_EMAIL = 0xCA,
+ TYPE_CCP1 = 0xCB
+};
+
+struct pb_file_info {
+ int file_id;
+ uint8_t file_type;
+ uint8_t structure;
+ int file_length;
+ int record_length;
+ int record;
+ gboolean handled;
+};
+
+struct file_info {
+ int fileid;
+ int length;
+ int structure;
+ int record_length;
+ unsigned char access[3];
+};
+
+struct phonebook_entry {
+ int entry;
+ char *name;
+ char *number;
+ char *email;
+ char *anr;
+ char *sne;
+};
+
+struct pb_data {
+ GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
+ gint pb_entry;
+ struct pb_file_info pb_reference_file_info;
+ struct pb_file_info *extension_file_info;
+ uint8_t ext1_to_type;
+ uint8_t ext1_to_entry;
+};
+
+static GSList *pb_files;
+static GSList *pb_next;
+
+static GSList *phonebook_entry_start;
+static GSList *phonebook_entry_current;
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data);
+static void pb_content_data_read(struct pb_data *pbd,
+ struct pb_file_info *file_info,
+ struct isi_cb_data *cbd);
+
static gboolean parse_adn(GIsiSubBlockIter *iter, uint16_t *location,
char **name, char **number)
{
@@ -194,6 +294,405 @@ error:
return success;
}
+static void handle_ext1(struct pb_data *pbd, const unsigned char *msg);
+
+static void handle_ext1(struct pb_data *pbd, const unsigned char *msg)
+{
+ uint8_t number_length = 0, i, next_extension_record;
+ static const char digit_to_utf8[] = "0123456789*#pwe\0";
+ struct pb_file_info *next_file = NULL;
+
+ char *ext_number = g_try_malloc0(EXT_NUMBER_SIZE);
+ if (ext_number != NULL) {
+ number_length = msg[1];
+ for (i = 0; i < number_length; i++) {
+ ext_number[2 * i] = digit_to_utf8[msg[2 + i] & 0x0f];
+ ext_number[2 * i + 1] =
+ digit_to_utf8[(msg[2 + i] >> 4) &
+ 0x0f];
+
+ }
+ }
+ next_extension_record = msg[number_length + 2];
+
+ DBG("Number extension %s number length %d extension_record %d",
+ ext_number,
+ number_length,
+ next_extension_record);
+
+ /* pb_entry is already incremented & g_slist_nth counts from 0 */
+ if (pbd->ext1_to_type == TYPE_ADN) {
+ GSList *list_entry = g_slist_nth(phonebook_entry_start,
+ pbd->ext1_to_entry -
+ 1);
+ DBG("Looking for ADN entry %d", pbd->ext1_to_entry);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry = list_entry->data;
+
+ if (entry != NULL)
+ strcat(entry->number, ext_number);
+ else if (pbd->ext1_to_type == TYPE_ANR) {
+ GSList *list_entry = g_slist_nth(
+ phonebook_entry_start,
+ pbd->ext1_to_entry - 1);
+ DBG("Looking for ANR entry %d",
+ pbd->ext1_to_entry);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL)
+ strcat(entry->anr, ext_number);
+ }
+ }
+ g_free(ext_number);
+ /* Check if there is more extension data */
+ if (next_extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info,
+ 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->extension_file_info,
+ sizeof(struct pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+ next_file->record =
+ next_extension_record;
+ }
+ }
+ }
+ }
+}
+
+static struct pb_file_info *decode_read_response(
+ struct pb_file_info *file_info,
+ const unsigned char *msg,
+ size_t len,
+ struct ofono_phonebook *pb)
+{
+ char *name = NULL;
+ char *number = NULL;
+ char *email = NULL;
+ char *sne = NULL;
+ char *anr = NULL;
+
+ static const char digit_to_utf8[] = "0123456789*#pwe\0";
+
+ struct pb_file_info *next_file = NULL;
+ int type = file_info->file_type;
+ struct pb_data *pbd = ofono_phonebook_get_data(pb);
+
+ switch (type) {
+ case TYPE_ADN:{
+ const uint8_t name_length = len - 14;
+ const uint8_t number_start = name_length;
+ uint8_t number_length = 0;
+ uint8_t extension_record = UNUSED;
+ uint8_t i, prefix;
+ name = sim_string_to_utf8(msg, name_length);
+ /* Length contains also TON&NPI */
+ number_length = msg[number_start];
+
+ if ((number_length != UNUSED) && (number_length != 0)) {
+ number = g_try_malloc0(NUMBER_SIZE);
+ number_length--;
+
+ if (number) {
+ prefix = 0;
+
+ if ((msg[number_start + 1] & TON_MASK)
+ == TON_INTERNATIONAL) {
+ number[0] = '+';
+ prefix = 1;
+ }
+
+ for (i = 0; i < number_length; i++) {
+
+ number[2 * i + prefix] =
+ digit_to_utf8[msg
+ [number_start
+ + 2 +
+ i] & 0x0f];
+
+ number[2 * i + 1 + prefix] =
+ digit_to_utf8[(msg
+ [number_start
+ + 2 +
+ i] >> 4) &
+ 0x0f];
+ }
+ extension_record = msg[len - 1];
+ }
+ }
+ DBG("ADN name %s, number %s number \
+ length %d extension_record %d",
+ name, number, number_length, extension_record);
+
+ if (extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info, 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->
+ extension_file_info,
+ sizeof(struct
+ pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+
+ next_file->record = extension_record;
+ pbd->ext1_to_type = TYPE_ADN;
+ pbd->ext1_to_entry = pbd->pb_entry;
+ }
+ }
+
+ if (name || number) {
+ struct phonebook_entry *new_entry =
+ g_try_new0(struct phonebook_entry, 1);
+
+ if (new_entry != NULL) {
+ new_entry->name = name;
+ new_entry->number = number;
+
+ DBG("Creating PB entry %d with \
+ name %s and number %s",
+ pbd->pb_entry,
+ new_entry->name,
+ new_entry->number);
+
+ phonebook_entry_current =
+ g_slist_insert
+ (phonebook_entry_start,
+ new_entry,
+ pbd->pb_entry);
+
+ if (!phonebook_entry_start)
+ phonebook_entry_start =
+ phonebook_entry_current;
+
+ pbd->pb_entry++;
+ }
+ }
+ break;
+ }
+ case TYPE_SNE:{
+ uint8_t sne_end = 0;
+ const uint8_t sne_length = len - 2;
+ uint8_t i = 0;
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+
+ DBG("SNE");
+ for (i = 0; (msg[i] != UNUSED) && (i < sne_length);
+ i++)
+ ;
+
+ sne_end = i;
+ sne = sim_string_to_utf8(msg, sne_length);
+
+ if (sne != NULL) {
+ /*
+ * GSlist nth counts from 0,
+ * PB entries from 1
+ */
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr -
+ 1);
+
+ DBG("SNE \'%s\' to PB entry %d", sne,
+ phonebook_entry_nbr);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ /*
+ * If one already exists,
+ * delete it
+ */
+ if (entry->sne != NULL)
+ g_free(entry->sne);
+
+ DBG("Adding SNE to entry %d,\
+ name %s",
+ phonebook_entry_nbr,
+ entry->name);
+
+ entry->sne = sne;
+ } else {
+ g_free(sne);
+ }
+ }
+ }
+
+ break;
+ }
+ case TYPE_ANR:{
+ uint8_t number_length = 0;
+ uint8_t extension_record = UNUSED;
+ uint8_t aas_record = UNUSED;
+ uint8_t i, prefix;
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+ GSList *list_entry;
+
+ DBG("ANR");
+ if (msg[0] == UNUSED)
+ break;
+
+ aas_record = msg[0];
+ /* Length contains also TON&NPI */
+ number_length = msg[1];
+
+ if (number_length) {
+ number_length--;
+ anr = g_try_malloc0(NUMBER_SIZE);
+
+ if (anr != NULL) {
+ prefix = 0;
+
+ if ((msg[2] & TON_MASK) ==
+ TON_INTERNATIONAL) {
+ anr[0] = '+';
+ prefix = 1;
+ }
+
+ for (i = 0; i < number_length; i++) {
+ anr[2 * i + prefix] =
+ digit_to_utf8[
+ msg[3 + i] &
+ 0x0f];
+ anr[2 * i + 1 + prefix] =
+ digit_to_utf8[
+ (msg[3 + i] >>
+ 4) & 0x0f];
+ }
+
+ extension_record = msg[len - 3];
+ }
+ }
+
+ DBG("ANR to entry %d number %s number length %d\
+ extension_record %d aas %d",
+ phonebook_entry_nbr, anr, number_length,
+ extension_record, aas_record);
+
+ if (extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info, 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->
+ extension_file_info,
+ sizeof(struct
+ pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+
+ next_file->record = extension_record;
+ pbd->ext1_to_type = TYPE_ANR;
+ pbd->ext1_to_entry =
+ phonebook_entry_nbr;
+ }
+ }
+
+ /* GSlist nth counts from 0, PB entries from 1 */
+ list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr - 1);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ /* if one already exists, delete it */
+ if (entry->anr)
+ g_free(entry->anr);
+
+ DBG("Adding ANR to entry %d, name %s",
+ phonebook_entry_nbr,
+ entry->name);
+ entry->anr = anr;
+ }
+ } else {
+ g_free(anr);
+ }
+
+ break;
+ }
+ case TYPE_AAS:{
+ DBG("AAS");
+ break;
+ }
+ case TYPE_EMAIL:{
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+ email = sim_string_to_utf8(msg, len - 2);
+
+ /* GSlist nth counts from 0, PB entries from 1 */
+ if (email != NULL) {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr - 1);
+
+ DBG("Email \'%s\' to PB entry %d", email,
+ phonebook_entry_nbr);
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ /* if one already exists, delete it */
+ if (entry != NULL) {
+ if (entry->email)
+ g_free(entry->email);
+
+ DBG("Adding email to entry %d,\
+ name %s",
+ phonebook_entry_nbr,
+ entry->name);
+
+ entry->email = email;
+ }
+ } else {
+ g_free(email);
+ }
+ }
+
+ break;
+ }
+ case TYPE_EXT1:{
+ if (msg[0] == EXT1_ADDITIONAL_DATA)
+ handle_ext1(pbd, msg);
+ break;
+
+ }
+ default:{
+ DBG("Skipping type %02X", type);
+ break;
+ }
+ }
+
+ return next_file;
+}
+
static void read_next_entry(GIsiClient *client, uint16_t location,
GIsiNotifyFunc notify, void *data)
{
@@ -254,51 +753,751 @@ static void read_resp_cb(const GIsiMessage *msg, void *data)
g_free(cbd);
}
+struct pb_file_info *extension_file_info;
+
+static void pb_adn_sim_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd_outer = data;
+ struct isi_cb_data *cbd = NULL;
+ struct pb_file_info *file_info;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (cbd_outer == NULL)
+ goto out;
+
+ file_info = cbd_outer->user;
+ cbd = cbd_outer->data;
+
+ if (cbd == NULL)
+ return;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto out;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = (struct ofono_sim *)g_isi_modem_get_sim(modem);
+
+ if (extension_file_info != NULL)
+ file_info =
+ decode_read_response(extension_file_info, sdata,
+ length, pb);
+ else
+ file_info = decode_read_response(file_info, sdata, length, pb);
+
+ if (file_info != NULL) {
+ DBG("Reading extension file %04X, record %d",
+ file_info->file_id, file_info->record);
+ sim_drv->read_file_linear(sim, file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_adn_sim_data_cb, cbd_outer);
+
+ /* Delete if there is a previous one */
+ g_free(extension_file_info);
+ extension_file_info = file_info;
+ return;
+ } else {
+ g_free(extension_file_info);
+ extension_file_info = NULL;
+ file_info = cbd_outer->user;
+
+ if (file_info->record <
+ (file_info->file_length / file_info->record_length)) {
+
+ file_info->record++;
+ DBG("Same file, next record %d", file_info->record);
+ sim_drv->read_file_linear(sim, file_info->file_id,
+ file_info->record,
+ file_info->
+ record_length,
+ pb_adn_sim_data_cb,
+ cbd_outer);
+ } else {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start, 0);
+ DBG("All data requested, start vCard creation");
+ g_free(file_info);
+
+ while (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ DBG("vCard:\nname=%s\nnumber=%s\n\
+ email=%s\nanr=%s\nsne=%s",
+ entry->name, entry->number,
+ entry->email, entry->anr,
+ entry->sne);
+
+ ofono_phonebook_entry(pb, -1,
+ entry->number,
+ -1,
+ entry->name,
+ -1,
+ NULL,
+ entry->anr, -1,
+ entry->sne,
+ entry->email,
+ NULL, NULL);
+ g_free(entry->number);
+ g_free(entry->name);
+ g_free(entry->anr);
+ g_free(entry->sne);
+ g_free(entry->email);
+ g_free(entry);
+ }
+
+ list_entry = g_slist_next(list_entry);
+ }
+
+ g_slist_free(phonebook_entry_start);
+ g_slist_free(pb_files);
+ g_free(cbd_outer);
+ DBG("Finally all PB data read");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ goto out;
+ }
+ }
+
+ return;
+out:
+ g_free(cbd);
+}
+
+static void pb_adn_sim_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb = cbd->user;
+ ofono_phonebook_cb_t cb = cbd->cb;
+ struct pb_data *pbd = ofono_phonebook_get_data(pb);
+ struct pb_file_info *file_info = NULL;
+ struct isi_cb_data *cbd_outer;
+ int records = 0;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+ file_info = NULL;
+
+ if (pbd == NULL)
+ goto error;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = g_isi_modem_get_sim(modem);
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ sim_drv->read_file_linear == NULL)
+ goto error;
+
+ records = filelength / recordlength;
+
+ if (records == 0)
+ goto error;
+
+ file_info = g_try_new0(struct pb_file_info, 1);
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->file_id = SIM_EFADN_FILEID;
+ file_info->file_type = TYPE_ADN;
+ file_info->structure = structure;
+ file_info->file_length = filelength;
+ file_info->record_length = recordlength;
+ file_info->record = 1;
+
+ /* Regenerate cbd (include file_info) */
+ cbd_outer = isi_cb_data_new(file_info, cb, cbd);
+ sim_drv->read_file_linear(sim, file_info->file_id, file_info->record,
+ file_info->record_length,
+ pb_adn_sim_data_cb, cbd_outer);
+ return;
+error:
+
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
+static gboolean is_reading_required(uint8_t file_type)
+{
+ switch (file_type) {
+ case TYPE_ADN:
+ case TYPE_EMAIL:
+ case TYPE_SNE:
+ case TYPE_ANR:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static void pb_content_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ struct pb_file_info *file_info = NULL;
+
+ if (cbd == NULL)
+ goto out;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (extension_file_info != NULL)
+ file_info = decode_read_response(extension_file_info, sdata,
+ length, pb);
+ else
+ file_info =
+ decode_read_response(pb_next->data, sdata, length, pb);
+
+ if (file_info != NULL) {
+ DBG("Reading extension file %04X, record %d, structure %d",
+ file_info->file_id, file_info->record,
+ file_info->structure);
+ pb_content_data_read(pbd, file_info, cbd);
+ /* Delete if there is a previous one */
+ g_free(extension_file_info);
+ extension_file_info = file_info;
+ return;
+ } else {
+ g_free(extension_file_info);
+ extension_file_info = NULL;
+ file_info = pb_next->data;
+
+ if (((file_info->structure ==
+ OFONO_SIM_FILE_STRUCTURE_FIXED) ||
+ (file_info->structure ==
+ OFONO_SIM_FILE_STRUCTURE_CYCLIC))
+ && (file_info->record <
+ (file_info->file_length / file_info->record_length))) {
+
+ file_info->record++;
+ DBG("Same file, next record %d", file_info->record);
+ } else {
+ g_free(file_info);
+ pb_next = g_slist_next(pb_next);
+ DBG("Next file in list");
+
+ if (pb_next != NULL) {
+ file_info = pb_next->data;
+
+ while ((pb_next != NULL) &&
+ (!is_reading_required(
+ file_info->file_type))) {
+ DBG("Skipping file type %02X",
+ file_info->file_type);
+ g_free(file_info);
+ pb_next = g_slist_next(pb_next);
+
+ if (pb_next)
+ file_info = pb_next->data;
+ }
+ }
+
+ if (pb_next == NULL) {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start, 0);
+
+ DBG("All data requested, start vCard creation");
+ while (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ DBG("vCard:\nname=%s\n \
+ number=%s\nemail=%s\n \
+ anr=%s\nsne=%s",
+ entry->name,
+ entry->number,
+ entry->email,
+ entry->anr,
+ entry->sne);
+
+ ofono_phonebook_entry(pb, -1,
+ entry->number,
+ -1,
+ entry->name,
+ -1,
+ NULL,
+ entry->anr,
+ -1,
+ entry->sne,
+ entry->email,
+ NULL,
+ NULL);
+
+ g_free(entry->number);
+ g_free(entry->name);
+ g_free(entry->anr);
+ g_free(entry->sne);
+ g_free(entry->email);
+ g_free(entry);
+ }
+
+ list_entry = g_slist_next(list_entry);
+ }
+
+ g_slist_free(phonebook_entry_start);
+ g_slist_free(pb_files);
+ DBG("Finally all PB data read");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ goto out;
+ }
+
+ file_info = pb_next->data;
+ }
+ }
+
+ pb_content_data_read(pbd, file_info, cbd);
+ return;
+out:
+ g_free(cbd);
+}
+
+static void pb_content_data_read(struct pb_data *pbd,
+ struct pb_file_info *file_info,
+ struct isi_cb_data *cbd)
+{
+ ofono_phonebook_cb_t cb;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (pbd == NULL || file_info == NULL || cbd == NULL)
+ return;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = g_isi_modem_get_sim(modem);
+
+ cb = cbd->cb;
+ DBG("Reading content of file type=%02X, file ID=%04X, structure=%d",
+ file_info->file_type, file_info->file_id, file_info->structure);
+
+ switch (file_info->structure) {
+ case OFONO_SIM_FILE_STRUCTURE_FIXED:
+
+ if (sim_drv->read_file_linear == NULL)
+ goto error;
+
+ sim_drv->read_file_linear(sim, file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_content_data_cb, cbd);
+ break;
+ case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
+
+ if (sim_drv->read_file_cyclic == NULL)
+ goto error;
+
+ sim_drv->read_file_cyclic(sim, file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_content_data_cb, cbd);
+ break;
+ case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
+
+ if (sim_drv->read_file_transparent == NULL)
+ goto error;
+
+ sim_drv->read_file_transparent(sim, file_info->file_id, 0,
+ file_info->file_length,
+ pb_content_data_cb,
+ cbd);
+ break;
+ }
+
+ return;
+error:
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+}
+
+static void pb_content_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ struct pb_file_info *file_info = NULL;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = g_isi_modem_get_sim(modem);
+
+ file_info = pb_next->data;
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->structure = structure;
+ file_info->file_length = filelength;
+ file_info->record_length = recordlength;
+ file_info->record = 1;
+
+ DBG("File type=%02X, File ID=%04X, Struct=%d, File len=%d, Rec len=%d",
+ file_info->file_type, file_info->file_id, file_info->structure,
+ file_info->file_length, file_info->record_length);
+
+ if (file_info->file_type == TYPE_EXT1)
+ /* Save for quick access */
+ pbd->extension_file_info = file_info;
+
+ pb_next = g_slist_next(pb_next);
+
+ if (pb_next == NULL) {
+ DBG("All info requested, start content reading");
+
+ /* Re-start from beginning */
+ pb_next = g_slist_nth(pb_files, 0);
+ file_info = pb_next->data;
+
+ DBG("Calling pb_content_data_read pb=%p, list=%p, type=%02X",
+ cbd->user, pb_next, file_info->file_type);
+
+ pb_content_data_read(pbd, file_info, cbd);
+ return;
+ }
+
+ file_info = pb_next->data;
+
+ DBG("Reading next content info %04X", file_info->file_id);
+ sim_drv->read_file_info(sim, file_info->file_id,
+ pb_content_info_cb, cbd);
+ return;
+error:
+
+ if (cbd != NULL) {
+ DBG("Error cbd=%p, pbd=%p, file_info=%p", cbd, pbd, file_info);
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+
+ g_free(cbd);
+}
+
+static void pb_reference_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ const unsigned char *ptr = sdata;
+ int typelen = 0;
+ int i = 0;
+ int file_id = 0;
+ gboolean finished = FALSE;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+
+ if (cb == NULL || pb == NULL)
+ goto out;
+
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = g_isi_modem_get_sim(modem);
+
+ while ((ptr < sdata + length) && (finished == FALSE)) {
+ switch (*ptr) {
+ case TYPE_1_TAG:
+ case TYPE_2_TAG:
+ case TYPE_3_TAG:
+ typelen = *(ptr + 1);
+ DBG("File type=%02X, len=%d", *ptr, typelen);
+ ptr += 2;
+ i = 0;
+
+ while (i < typelen) {
+ struct pb_file_info *file_info =
+ g_try_new0(struct pb_file_info, 1);
+ file_id = (ptr[i + 2] << 8) + ptr[i + 3];
+
+ DBG("creating file info for File type=%02X,\
+ File ID=%04X",
+ ptr[i],
+ file_id);
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->file_type = ptr[i];
+ file_info->file_id = file_id;
+ pb_files =
+ g_slist_append(pb_files,
+ (void *)file_info);
+ i += ptr[i + 1] + 2;
+ }
+
+ ptr += typelen;
+ break;
+ default:
+ DBG("All handled %02x", *ptr);
+ finished = TRUE;
+ break;
+ }
+ }
+
+ if (pbd->pb_reference_file_info.record <
+ (pbd->pb_reference_file_info.file_length /
+ pbd->pb_reference_file_info.record_length)) {
+ pbd->pb_reference_file_info.record++;
+ DBG("Next EFpbr record %d", pbd->pb_reference_file_info.record);
+ sim_drv->read_file_linear(sim,
+ pbd->pb_reference_file_info.file_id,
+ pbd->pb_reference_file_info.record,
+ pbd->pb_reference_file_info.record_length,
+ pb_reference_data_cb, cbd);
+ } else {
+ struct pb_file_info *file_info;
+ DBG("All EFpbr records read");
+ pb_next = g_slist_nth(pb_files, 0);
+
+ if (pb_next == NULL)
+ goto error;
+
+ file_info = pb_next->data;
+
+ if ((file_info == NULL)) /*|| !pbd->sim_func)*/
+ goto error;
+
+ sim_drv->read_file_info(sim, file_info->file_id,
+ pb_content_info_cb, cbd);
+ }
+
+ return;
+error:
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+ g_free(cbd);
+}
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status,
+ void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ int records = 0;
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
+ GIsiModem *modem;
+ struct ofono_sim *sim;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ modem = g_isi_client_modem(pbd->client);
+ sim = g_isi_modem_get_sim(modem);
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+ goto error;
+
+ if (sim_drv == NULL || sim_drv->read_file_linear == NULL)
+ goto error;
+
+ records = filelength / recordlength;
+
+ if (records == 0)
+ goto error;
+
+ DBG("EFpbr size %d, record length %d, records %d",
+ filelength, recordlength, records);
+ pbd->pb_reference_file_info.file_id = SIM_EFPBR_FILEID;
+ pbd->pb_reference_file_info.file_length = filelength;
+ pbd->pb_reference_file_info.record_length = recordlength;
+ pbd->pb_reference_file_info.record = 1; /* Current record, not amount*/
+ pbd->pb_reference_file_info.structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
+ sim_drv->read_file_linear(sim, SIM_EFPBR_FILEID, 1, recordlength,
+ pb_reference_data_cb, cbd);
+ return;
+error:
+
+ if ((cb != NULL) && (cbd != NULL))
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
static void isi_export_entries(struct ofono_phonebook *pb, const char *storage,
ofono_phonebook_cb_t cb, void *data)
{
struct pb_data *pbd = ofono_phonebook_get_data(pb);
struct isi_cb_data *cbd = isi_cb_data_new(pb, cb, data);
- const uint8_t msg[] = {
- SIM_PB_REQ_SIM_PB_READ,
- SIM_PB_READ,
- 2, /* number of subblocks */
- 0, SIM_PB_LOCATION, /* subblock id */
- 0, 8, /* subblock size */
- 0, SIM_PB_ADN,
- 0xFF, 0xFF, /* read first entry in pb */
- 0, SIM_PB_INFO_REQUEST, /* subblock id */
- 0, 16, /* subblock size */
- 4, /* number of tags */
- 0, /* filler */
- 0, SIM_PB_ADN, /* tags */
- 0, SIM_PB_SNE,
- 0, SIM_PB_ANR,
- 0, SIM_PB_EMAIL,
- 0, 0 /* filler */
- };
- size_t len = sizeof(msg);
+ GIsiModem *modem = g_isi_client_modem(pbd->client);
+ struct ofono_sim *sim = g_isi_modem_get_sim(modem);
+ struct ofono_sim_driver *sim_drv = get_sim_driver_func();
- if (cbd == NULL || pbd == NULL || strcmp(storage, "SM") != 0)
+ if (cbd == NULL || pbd == NULL)
goto error;
- if (g_isi_client_send(pbd->client, msg, len, read_resp_cb, cbd, NULL))
- return;
-
+ if (g_isi_client_resource(pbd->client) == PN_UICC) {
+ pbd->pb_entry = 1;
+ pb_files = NULL;
+ pb_next = NULL;
+ phonebook_entry_current = NULL;
+ phonebook_entry_start = NULL;
+
+ switch (get_app_type(modem)) {
+ case UICC_APPL_TYPE_ICC_SIM:
+ DBG("SIM application");
+ sim_drv->read_file_info(sim,
+ SIM_EFADN_FILEID,
+ pb_adn_sim_info_cb,
+ cbd);
+ break;
+ case UICC_APPL_TYPE_UICC_USIM:
+ DBG("USIM application");
+ sim_drv->read_file_info(sim,
+ SIM_EFPBR_FILEID,
+ pb_reference_info_cb,
+ cbd);
+ break;
+ default:
+ DBG("UICC application type not unknown or supported");
+ goto error;
+ break;
+ }
+ } else {
+
+ const uint8_t msg[] = {
+ SIM_PB_REQ_SIM_PB_READ,
+ SIM_PB_READ,
+ 2, /* number of subblocks */
+ 0, SIM_PB_LOCATION, /* subblock id */
+ 0, 8, /* subblock size */
+ 0, SIM_PB_ADN,
+ 0xFF, 0xFF, /* read first entry in pb */
+ 0, SIM_PB_INFO_REQUEST, /* subblock id */
+ 0, 16, /* subblock size */
+ 4, /* number of tags */
+ 0, /* filler */
+ 0, SIM_PB_ADN, /* tags */
+ 0, SIM_PB_SNE,
+ 0, SIM_PB_ANR,
+ 0, SIM_PB_EMAIL,
+ 0, 0 /* filler */
+ };
+ size_t len = sizeof(msg);
+
+ if (strcmp(storage, "SM") != 0)
+ goto error;
+
+ if (g_isi_client_send(pbd->client, msg, len, read_resp_cb,
+ cbd, NULL))
+ return;
+ }
+ return;
error:
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
-static void reachable_cb(const GIsiMessage *msg, void *data)
+static void primary_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_phonebook *pb = data;
+ struct pb_data *pd = ofono_phonebook_get_data(pb);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+ pd->client = pd->primary;
+
+ g_isi_client_destroy(pd->secondary);
+
+ ofono_phonebook_register(pb);
+}
+
+static void secondary_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_phonebook *pb = data;
+ struct pb_data *pd = ofono_phonebook_get_data(pb);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ pd->client = pd->secondary;
+
+ g_isi_client_destroy(pd->primary);
+
ofono_phonebook_register(pb);
}
@@ -312,15 +1511,23 @@ static int isi_phonebook_probe(struct ofono_phonebook *pb, unsigned int vendor,
if (data == NULL)
return -ENOMEM;
- data->client = g_isi_client_create(modem, PN_SIM);
- if (data->client == NULL) {
+ data->primary = g_isi_client_create(modem, PN_UICC);
+ if (data->primary == NULL) {
+ g_free(data);
+ return -ENOMEM;
+ }
+
+ data->secondary = g_isi_client_create(modem, PN_SIM);
+ if (data->secondary == NULL) {
+ g_isi_client_destroy(data->primary);
g_free(data);
return -ENOMEM;
}
ofono_phonebook_set_data(pb, data);
- g_isi_client_verify(data->client, reachable_cb, pb, NULL);
+ g_isi_client_verify(data->primary, primary_reachable_cb, pb, NULL);
+ g_isi_client_verify(data->secondary, secondary_reachable_cb, pb, NULL);
return 0;
}
@@ -329,12 +1536,18 @@ static void isi_phonebook_remove(struct ofono_phonebook *pb)
{
struct pb_data *data = ofono_phonebook_get_data(pb);
+ pb_files = NULL;
+ pb_next = NULL;
+ phonebook_entry_start = NULL;
+ phonebook_entry_current = NULL;
+
ofono_phonebook_set_data(pb, NULL);
if (data == NULL)
return;
g_isi_client_destroy(data->client);
+
g_free(data);
}
--
1.7.3.5
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 02/18] isimodem: added codepoints for u8500
2011-02-23 11:43 ` [PATCH v2 02/18] isimodem: added codepoints for u8500 Andreas Westin
@ 2011-02-23 13:17 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-23 13:17 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 333 bytes --]
Hi Andreas,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/debug.c | 1 +
> drivers/isimodem/info.h | 3 +++
> 2 files changed, 4 insertions(+), 0 deletions(-)
Patch has been pushed. Thanks.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 03/18] plugins: add plugin for u8500
2011-02-23 11:43 ` [PATCH v2 03/18] plugins: add plugin " Andreas Westin
@ 2011-02-23 13:26 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-23 13:26 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 26582 bytes --]
Hi Andreas,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> Makefile.am | 3 +
> plugins/u8500.c | 708 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 711 insertions(+), 0 deletions(-)
> create mode 100644 plugins/u8500.c
I pushed this patch, but split it into two, and fixed the plugin
description afterwards.
Cheers,
Aki
> diff --git a/Makefile.am b/Makefile.am
> index 7bd7f4f..aa4f3f9 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -144,6 +144,9 @@ builtin_sources += plugins/isiusb.c
>
> builtin_modules += n900
> builtin_sources += plugins/n900.c plugins/nokia-gpio.h plugins/nokia-gpio.c
> +
> +builtin_modules += u8500
> +builtin_sources += plugins/u8500.c
> endif
>
> if ATMODEM
> diff --git a/plugins/u8500.c b/plugins/u8500.c
> new file mode 100644
> index 0000000..78e1a97
> --- /dev/null
> +++ b/plugins/u8500.c
> @@ -0,0 +1,708 @@
> +/*
> + *
> + * oFono - Open Source Telephony
> + *
> + * Copyright (C) 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
> + * 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
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <glib.h>
> +
> +#include <gisi/netlink.h>
> +#include <gisi/modem.h>
> +#include <gisi/client.h>
> +#include <gisi/message.h>
> +#include <gisi/iter.h>
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#include <ofono/plugin.h>
> +#include <ofono/log.h>
> +#include <ofono/modem.h>
> +#include <ofono/devinfo.h>
> +#include <ofono/phonebook.h>
> +#include <ofono/netreg.h>
> +#include <ofono/voicecall.h>
> +#include <ofono/sms.h>
> +#include <ofono/cbs.h>
> +#include <ofono/sim.h>
> +#include <ofono/ussd.h>
> +#include <ofono/ssn.h>
> +#include <ofono/call-forwarding.h>
> +#include <ofono/call-settings.h>
> +#include <ofono/call-barring.h>
> +#include <ofono/call-meter.h>
> +#include <ofono/radio-settings.h>
> +#include <ofono/gprs.h>
> +#include <ofono/gprs-context.h>
> +
> +#include "drivers/isimodem/isimodem.h"
> +#include "drivers/isimodem/isiutil.h"
> +#include "drivers/isimodem/mtc.h"
> +#include "drivers/isimodem/debug.h"
> +
> +struct isi_data {
> + char const *ifname;
> + GIsiModem *modem;
> + GIsiClient *client;
> + GIsiPhonetNetlink *link;
> + enum GIsiPhonetLinkState linkstate;
> + unsigned interval;
> + int reported;
> + ofono_bool_t online;
> + struct isi_cb_data *online_cbd;
> +};
> +
> +struct devinfo_data {
> + GIsiClient *client;
> +};
> +
> +static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
> +{
> + 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",
> + mce_message_id_name(g_isi_msg_id(msg)));
> + return FALSE;
> + }
> + return TRUE;
> +}
> +
> +static void report_powered(struct ofono_modem *modem, struct isi_data *isi,
> + ofono_bool_t powered)
> +{
> + if (powered == isi->reported)
> + return;
> +
> + isi->reported = powered;
> + ofono_modem_set_powered(modem, powered);
> +}
> +
> +static void report_online(struct isi_data *isi, ofono_bool_t online)
> +{
> + struct isi_cb_data *cbd = isi->online_cbd;
> + ofono_modem_online_cb_t cb = cbd->cb;
> +
> + isi->online_cbd = NULL;
> +
> + if (isi->online == online)
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + else
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> +
> + g_free(cbd);
> +}
> +
> +static void set_power_by_mce_state(struct ofono_modem *modem,
> + struct isi_data *isi, int mce_state)
> +{
> + switch (mce_state) {
> + case MCE_POWER_OFF:
> + report_powered(modem, isi, FALSE);
> + break;
> + case MCE_NORMAL:
> + if (isi->online_cbd)
> + report_online(isi, mce_state == MCE_NORMAL);
> + default:
> + report_powered(modem, isi, TRUE);
> + }
> +}
> +
> +static void mce_state_ind_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_modem *modem = data;
> + struct isi_data *isi = ofono_modem_get_data(modem);
> + uint8_t state;
> + uint8_t action;
> +
> + if (isi == NULL || g_isi_msg_id(msg) != MCE_MODEM_STATE_IND)
> + return;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
> + !g_isi_msg_data_get_byte(msg, 1, &action))
> + return;
> +
> + switch (action) {
> + case MCE_START:
> + DBG("target modem state: %s (0x%02X)",
> + mce_modem_state_name(state), state);
> + break;
> +
> + case MCE_READY:
> + DBG("current modem state: %s (0x%02X)",
> + mce_modem_state_name(state), state);
> + set_power_by_mce_state(modem, isi, state);
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static void mce_rf_state_ind_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_modem *modem = data;
> + struct isi_data *isi = ofono_modem_get_data(modem);
> + uint8_t state;
> + uint8_t action;
> +
> + if (isi == NULL || g_isi_msg_id(msg) != MCE_RF_STATE_IND)
> + return;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
> + !g_isi_msg_data_get_byte(msg, 1, &action))
> + return;
> +
> + switch (action) {
> + case MCE_READY:
> + DBG("current rf state: %s (0x%02X)",
> + mce_rf_state_name(state), state);
> + if (isi->online_cbd)
> + report_online(isi, state);
> + break;
> + case MCE_START:
> + default:
> + break;
> + }
> +}
> +
> +static void mce_query_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_modem *modem = data;
> + struct isi_data *isi = ofono_modem_get_data(modem);
> + uint8_t current;
> + uint8_t target;
> +
> + if (!check_response_status(msg, MCE_MODEM_STATE_QUERY_RESP))
> + return;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, ¤t) ||
> + !g_isi_msg_data_get_byte(msg, 1, &target))
> + return;
> +
> + DBG("Modem state: current=%s (0x%02X) target=%s (0x%02X)",
> + mce_modem_state_name(current), current,
> + mce_modem_state_name(target), target);
> +
> + if (current == target)
> + set_power_by_mce_state(modem, isi, current);
> +}
> +
> +static gboolean bootstrap_current_state(gpointer user)
> +{
> + struct ofono_modem *om = user;
> + struct isi_data *isi = ofono_modem_get_data(om);
> +
> + const uint8_t req[] = {
> + MCE_MODEM_STATE_QUERY_REQ,
> + 0x00, 0x00 /* Filler */
> + };
> + size_t len = sizeof(req);
> +
> + g_isi_client_send(isi->client, req, len, mce_query_cb, om, NULL);
> +
> + return FALSE;
> +}
> +
> +static void reachable_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_modem *om = data;
> + struct isi_data *isi = ofono_modem_get_data(om);
> +
> + if (!g_isi_msg_error(msg) < 0)
> + return;
> +
> + ISI_VERSION_DBG(msg);
> +
> + g_isi_client_ind_subscribe(isi->client, MCE_MODEM_STATE_IND,
> + mce_state_ind_cb, om);
> +
> + g_isi_client_ind_subscribe(isi->client, MCE_RF_STATE_IND,
> + mce_rf_state_ind_cb, om);
> +
> + /*
> + * FIXME: There is a theoretical race condition here:
> + * g_isi_client_ind_subscribe() adds the actual message
> + * sending for committing changes to subscriptions in idle
> + * loop, which may or may not preserve ordering. Thus, we
> + * might miss a state indication if the bootstrap request ends
> + * up being sent first.
> + */
> + g_idle_add(bootstrap_current_state, om);
> +}
> +
> +static void phonet_status_cb(GIsiModem *modem, enum GIsiPhonetLinkState st,
> + char const *ifname, void *data)
> +{
> + struct ofono_modem *om = data;
> + struct isi_data *isi = ofono_modem_get_data(om);
> +
> + DBG("Link %s (%u) is %s", isi->ifname, g_isi_modem_index(isi->modem),
> + st == PN_LINK_REMOVED ? "removed" :
> + st == PN_LINK_DOWN ? "down" : "up");
> +
> + isi->linkstate = st;
> +
> + if (st == PN_LINK_UP)
> + g_isi_client_verify(isi->client, reachable_cb, om, NULL);
> + else if (st == PN_LINK_DOWN)
> + set_power_by_mce_state(om, isi, MCE_POWER_OFF);
> +}
> +
> +static int u8500_probe(struct ofono_modem *modem)
> +{
> + const char *ifname = ofono_modem_get_string(modem, "Interface");
> + unsigned address = ofono_modem_get_integer(modem, "Address");
> + GIsiModem *isimodem;
> + GIsiClient *client = NULL;
> + GIsiPhonetNetlink *link = NULL;
> + struct isi_data *isi = NULL;
> +
> + if (ifname == NULL)
> + return -EINVAL;
> +
> + DBG("(%p) with %s", modem, ifname);
> +
> + isimodem = g_isi_modem_create_by_name(ifname);
> + if (isimodem == NULL) {
> + DBG("Interface=%s: %s", ifname, strerror(errno));
> + return -errno;
> + }
> +
> + g_isi_modem_set_userdata(isimodem, modem);
> +
> + if (getenv("OFONO_ISI_DEBUG"))
> + g_isi_modem_set_debug(isimodem, ofono_debug);
> +
> + if (getenv("OFONO_ISI_TRACE"))
> + g_isi_modem_set_trace(isimodem, isi_trace);
> +
> + if (g_isi_pn_netlink_by_modem(isimodem)) {
> + DBG("%s: %s", ifname, strerror(EBUSY));
> + errno = EBUSY;
> + goto error;
> + }
> +
> + link = g_isi_pn_netlink_start(isimodem, phonet_status_cb, modem);
> + if (link == NULL) {
> + DBG("%s: %s", ifname, strerror(errno));
> + goto error;
> + }
> +
> + if (address) {
> + int error = g_isi_pn_netlink_set_address(isimodem, address);
> + if (error && error != -EEXIST) {
> + DBG("g_isi_pn_netlink_set_address(): %s\n",
> + strerror(-error));
> + errno = -error;
> + goto error;
> + }
> + }
> +
> + isi = g_try_new0(struct isi_data, 1);
> + if (isi == NULL) {
> + errno = ENOMEM;
> + goto error;
> + }
> +
> + client = g_isi_client_create(isimodem, PN_MODEM_MCE);
> + if (!client)
> + goto error;
> +
> + g_isi_modem_set_device(isimodem, PN_DEV_MODEM);
> +
> + isi->modem = isimodem;
> + isi->ifname = ifname;
> + isi->link = link;
> + isi->reported = -1;
> + isi->client = client;
> +
> + ofono_modem_set_data(modem, isi);
> + return 0;
> +
> +error:
> + g_isi_pn_netlink_stop(link);
> + g_isi_client_destroy(client);
> + g_isi_modem_destroy(isimodem);
> + g_free(isi);
> +
> + return -errno;
> +}
> +
> +static void u8500_remove(struct ofono_modem *modem)
> +{
> + struct isi_data *isi = ofono_modem_get_data(modem);
> +
> + ofono_modem_set_data(modem, NULL);
> +
> + if (isi == NULL)
> + return;
> +
> + g_isi_pn_netlink_stop(isi->link);
> + g_isi_client_destroy(isi->client);
> + g_isi_modem_destroy(isi->modem);
> + g_free(isi);
> +}
> +
> +static void mce_state_cb(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + struct ofono_modem *modem = cbd->user;
> + ofono_modem_online_cb_t cb = cbd->cb;
> +
> + struct isi_data *isi = ofono_modem_get_data(modem);
> + uint8_t cause;
> +
> + if (!check_response_status(msg, MCE_RF_STATE_RESP))
> + goto error;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, &cause))
> + goto error;
> +
> + DBG("MCE cause: %s (0x%02X)", mce_status_info(cause), cause);
> +
> + if (cause == MCE_OK) {
> + isi->online_cbd = cbd;
> + return;
> + }
> +
> + if (cause == MCE_ALREADY_ACTIVE) {
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + g_free(cbd);
> + return;
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> + g_free(cbd);
> +}
> +
> +static void u8500_online(struct ofono_modem *modem, ofono_bool_t online,
> + ofono_modem_online_cb_t cb, void *data)
> +{
> + struct isi_data *isi = ofono_modem_get_data(modem);
> + struct isi_cb_data *cbd = isi_cb_data_new(modem, cb, data);
> + const uint8_t req[] = {
> + MCE_RF_STATE_REQ,
> + online ? MCE_RF_ON : MCE_RF_OFF,
> + 0x00
> + };
> +
> + DBG("(%p) with %s", modem, isi->ifname);
> +
> + if (cbd == NULL || isi == NULL)
> + goto error;
> +
> + if (g_isi_client_send_with_timeout(isi->client, req, sizeof(req),
> + MTC_STATE_REQ_TIMEOUT,
> + mce_state_cb, cbd, NULL)) {
> + isi->online = online;
> + return;
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> +}
> +
> +static void u8500_pre_sim(struct ofono_modem *modem)
> +{
> + struct isi_data *isi = ofono_modem_get_data(modem);
> +
> + DBG("(%p) with %s", modem, isi->ifname);
> +
> + ofono_sim_create(modem, 0, "isimodem", isi->modem);
> + ofono_devinfo_create(modem, 0, "u8500", isi->modem);
> + ofono_voicecall_create(modem, 0, "isimodem", isi->modem);
> +}
> +
> +static void u8500_post_sim(struct ofono_modem *modem)
> +{
> + struct isi_data *isi = ofono_modem_get_data(modem);
> +
> + DBG("(%p) with %s", modem, isi->ifname);
> +
> + ofono_phonebook_create(modem, 0, "isimodem", isi->modem);
> + ofono_call_forwarding_create(modem, 0, "isimodem", isi->modem);
> + ofono_radio_settings_create(modem, 0, "isimodem", isi->modem);
> +}
> +
> +static void u8500_post_online(struct ofono_modem *modem)
> +{
> + struct isi_data *isi = ofono_modem_get_data(modem);
> +
> + DBG("(%p) with %s", modem, isi->ifname);
> +
> + ofono_netreg_create(modem, 0, "wgmodem2.5", isi->modem);
> + ofono_sms_create(modem, 0, "isimodem", isi->modem);
> + ofono_cbs_create(modem, 0, "isimodem", isi->modem);
> + ofono_ssn_create(modem, 0, "isimodem", isi->modem);
> + ofono_ussd_create(modem, 0, "isimodem", isi->modem);
> + ofono_call_settings_create(modem, 0, "isimodem", isi->modem);
> + ofono_call_barring_create(modem, 0, "isimodem", isi->modem);
> + ofono_call_meter_create(modem, 0, "isimodem", isi->modem);
> + ofono_gprs_create(modem, 0, "isimodem", isi->modem);
> +}
> +
> +static int u8500_enable(struct ofono_modem *modem)
> +{
> + return 0;
> +}
> +
> +static int u8500_disable(struct ofono_modem *modem)
> +{
> + return 0;
> +}
> +
> +static void u8500_info_resp_cb(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_devinfo_query_cb_t cb = cbd->cb;
> + GIsiSubBlockIter iter;
> + uint8_t msgid;
> + uint8_t status;
> +
> + msgid = g_isi_msg_id(msg);
> + if (msgid != INFO_SERIAL_NUMBER_READ_RESP)
> + goto error;
> +
> + if (g_isi_msg_error(msg) < 0)
> + goto error;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, &status))
> + goto error;
> +
> + if (status != INFO_OK)
> + goto error;
> +
> + for (g_isi_sb_iter_init(&iter, msg, 2);
> + g_isi_sb_iter_is_valid(&iter);
> + g_isi_sb_iter_next(&iter)) {
> +
> + uint8_t id = g_isi_sb_iter_get_id(&iter);
> + uint8_t chars;
> + char *info = NULL;
> +
> + if (id != INFO_SB_PRODUCT_INFO_MANUFACTURER &&
> + id != INFO_SB_PRODUCT_INFO_NAME &&
> + id != INFO_SB_MCUSW_VERSION &&
> + id != INFO_SB_SN_IMEI_PLAIN &&
> + id != INFO_SB_MODEMSW_VERSION)
> + continue;
> +
> + if (g_isi_sb_iter_get_len(&iter) < 5)
> + goto error;
> +
> + if (!g_isi_sb_iter_get_byte(&iter, &chars, 3))
> + goto error;
> +
> + if (!g_isi_sb_iter_get_latin_tag(&iter, &info, chars, 4))
> + goto error;
> +
> + CALLBACK_WITH_SUCCESS(cb, info, cbd->data);
> +
> + g_free(info);
> + return;
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, "", cbd->data);
> +}
> +
> +static void u8500_devinfo_reachable_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_devinfo *info = data;
> +
> + if (g_isi_msg_error(msg) < 0)
> + return;
> +
> + ISI_VERSION_DBG(msg);
> +
> + ofono_devinfo_register(info);
> +}
> +
> +static void u8500_query_manufacturer(struct ofono_devinfo *info,
> + ofono_devinfo_query_cb_t cb,
> + void *data)
> +{
> + CALLBACK_WITH_FAILURE(cb, "", data);
> +}
> +
> +static void u8500_query_model(struct ofono_devinfo *info,
> + ofono_devinfo_query_cb_t cb,
> + void *data)
> +{
> + CALLBACK_WITH_FAILURE(cb, "", data);
> +}
> +
> +static void u8500_query_revision(struct ofono_devinfo *info,
> + ofono_devinfo_query_cb_t cb,
> + void *data)
> +{
> + struct devinfo_data *dev = ofono_devinfo_get_data(info);
> + struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
> + const unsigned char msg[] = {
> + INFO_SERIAL_NUMBER_READ_REQ,
> + 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x01, /* M_INFO_MODEMSW */
> + 0x00, 0x00
> + };
> + DBG("");
> +
> + if (cbd == NULL || dev == NULL)
> + goto error;
> +
> + if (g_isi_client_send(dev->client, msg, sizeof(msg),
> + u8500_info_resp_cb, cbd, g_free))
> + return;
> +
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, "", data);
> + g_free(cbd);
> +}
> +
> +static void u8500_query_serial(struct ofono_devinfo *info,
> + ofono_devinfo_query_cb_t cb,
> + void *data)
> +{
> + char imei[16]; /* IMEI 15 digits + 1 null*/
> + char numbers[] = "1234567890";
> + FILE *fp = fopen("/etc/imei", "r");
> + DBG("");
> +
> + if (fp == NULL) {
> + DBG("failed to open /etc/imei file");
> + goto error;
> + }
> +
> + if (fgets(imei, 16, fp)) {
> + DBG(" IMEI = %s", imei);
> + if (15 == strspn(imei, numbers))
> + CALLBACK_WITH_SUCCESS(cb, imei, data);
> + else {
> + CALLBACK_WITH_FAILURE(cb, "", data);
> + fclose(fp);
> + goto error;
> + }
> + }
> +
> + fclose(fp);
> + return;
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, "", data);
> +}
> +
> +static int u8500_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
> + void *user)
> +{
> + GIsiModem *idx = user;
> + struct devinfo_data *data = g_try_new0(struct devinfo_data, 1);
> +
> + if (data == NULL)
> + return -ENOMEM;
> +
> + data->client = g_isi_client_create(idx, PN_MODEM_INFO);
> + if (data->client == NULL)
> + goto nomem;
> +
> + ofono_devinfo_set_data(info, data);
> +
> + g_isi_client_set_timeout(data->client, INFO_TIMEOUT);
> + g_isi_client_verify(data->client, u8500_devinfo_reachable_cb,
> + info, NULL);
> +
> + return 0;
> +
> +nomem:
> + g_isi_client_destroy(data->client);
> +
> + g_free(data);
> + return -ENOMEM;
> +
> +}
> +
> +static void u8500_devinfo_remove(struct ofono_devinfo *info)
> +{
> + struct devinfo_data *data = ofono_devinfo_get_data(info);
> +
> + ofono_devinfo_set_data(info, NULL);
> +
> + if (data == NULL)
> + return;
> +
> + g_isi_client_destroy(data->client);
> + g_free(data);
> +}
> +
> +static struct ofono_modem_driver driver = {
> + .name = "u8500",
> + .probe = u8500_probe,
> + .remove = u8500_remove,
> + .set_online = u8500_online,
> + .pre_sim = u8500_pre_sim,
> + .post_sim = u8500_post_sim,
> + .post_online = u8500_post_online,
> + .enable = u8500_enable,
> + .disable = u8500_disable,
> +};
> +
> +static struct ofono_devinfo_driver devinfo_driver = {
> + .name = "u8500",
> + .probe = u8500_devinfo_probe,
> + .remove = u8500_devinfo_remove,
> + .query_manufacturer = u8500_query_manufacturer,
> + .query_model = u8500_query_model,
> + .query_revision = u8500_query_revision,
> + .query_serial = u8500_query_serial
> +};
> +
> +static int u8500_init(void)
> +{
> + int err;
> +
> + err = ofono_modem_driver_register(&driver);
> +
> + if (err < 0)
> + return err;
> +
> + ofono_devinfo_driver_register(&devinfo_driver);
> +
> + return 0;
> +}
> +
> +static void u8500_exit(void)
> +{
> + ofono_devinfo_driver_unregister(&devinfo_driver);
> +
> + ofono_modem_driver_unregister(&driver);
> +}
> +
> +OFONO_PLUGIN_DEFINE(u8500, "Generic modem driver for isi",
> + VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
> + u8500_init, u8500_exit)
> --
> 1.7.3.5
>
> _______________________________________________
> ofono mailing list
> ofono(a)ofono.org
> http://lists.ofono.org/listinfo/ofono
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5
2011-02-23 11:43 ` [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
@ 2011-02-25 15:20 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-25 15:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 137398 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/sim.c | 2678 ++++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 2480 insertions(+), 198 deletions(-)
>
> diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
> index bfecbc9..117129b 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,22 +34,211 @@
>
> #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
> +
> +#define ADF_USIM 0x7FFF
> +#define MAX_SIM_APPS 0x08
> +#define NOT_AVAILABLE -1
> +#define NOT_ACTIVATED -1
> +
> +/* File info parameters */
> +enum file_info_params {
> + FCP_TEMPLATE = 0x62,
> + FCP_FILE_SIZE = 0x80,
> + FCP_FILE_DESC = 0x82,
> + FCP_FILE_ID = 0x83,
> + FCP_FILE_LIFECYCLE = 0x8A,
> + FCP_FILE_SECURITY_ARR = 0x8B,
> + FCP_FILE_SECURITY_COMPACT = 0x8C,
> + FCP_FILE_SECURITY_EXPANDED = 0xAB,
> + FCP_PIN_STATUS = 0xC6,
> +};
> +
> +struct sim_applications {
> + int app_list[MAX_SIM_APPS];
> + int app_type[MAX_SIM_APPS];
> +};
>
> 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 sim_applications *sim_application_list_p;
> +};
> +
> +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;
> +};
This is completely inappropriate; struct ofono_sim is private on purpose.
> +
> +struct sim_passwd_to_pin_id {
> + int8_t passwd_type;
> + int8_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}
> +};
> +
> +const uint8_t upin_id = 0x11;
> +
> +struct file_info {
> + int fileid;
> + int length;
> + int structure;
> + int record_length;
> + uint8_t access[3];
> + uint8_t file_status;
> +};
> +
> +struct read_file_data {
> + struct file_info *info;
> + struct sim_data *sim_data;
> +};
> +
> +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 }
> + },
> };
>
> struct sim_imsi {
> @@ -66,14 +256,275 @@ 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 uint8_t fileid_to_short_fileid(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;
> +}
> +
> +static int sim_applications_get_next_index(struct sim_applications *sa,
> + int current_app)
> +{
> + int i;
> +
> + if (current_app >= (MAX_SIM_APPS - 1))
> + return NOT_AVAILABLE;
> +
> + for (i = ++current_app; i < MAX_SIM_APPS; i++) {
> +
> + if (sa->app_list[i] && (sa->app_type[i] !=
> + UICC_APPL_TYPE_UNKNOWN))
> + return i;
> + }
> +
> + return NOT_AVAILABLE;
> +}
> +
> +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;
> + }
> +}
Let's start from what exactly this is trying to do. You can't access
the sim atom's internal state, so there needs to be another way to do
whatever this is trying to do.
> +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;
> +}
> +
> +int get_app_id(GIsiModem *modem)
> +{
> + struct ofono_sim *sim;
> +
> + if (modem == NULL)
> + return -1;
> +
> + sim = g_isi_modem_get_sim(modem);
> +
> + if (sim) {
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + return sd->app_id;
> + } else
> + return -1;
> +}
> +
> +int get_app_type(GIsiModem *modem)
> +{
> + struct ofono_sim *sim;
> +
> + if (modem == NULL)
> + return -1;
> +
> + sim = g_isi_modem_get_sim(modem);
> +
> + if (sim) {
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + return sd->app_type;
> + } else
> + return -1;
> +}
> +
> +int get_client_id(GIsiModem *modem)
> +{
> + struct ofono_sim *sim;
> +
> + if (modem == NULL)
> + return -1;
> +
> + sim = g_isi_modem_get_sim(modem);
> +
> + if (sim) {
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + return sd->client_id;
> + } else
> + return -1;
> +}
What I meant was that this driver should keep track of all of the
instances of SIM drivers, e.g., using a modem->driver hash table. Then
the API would not require GIsiModem to store any pointers, instead,
you would use a pointer to the GIsiModem as key to the hash table.
In any case, I'd like this to be just have a single function call,
like a isi_uicc_properties() taking output params as arguments and
returning a gboolean.
That said, this would be a whole lot simpler to implement by having a
separate uiccutils.c that contains the necessary UICC_APPL_LIST and
UICC_APPL_HOST_ACTIVATE response decoders, and have both the SIM
driver and the SMS driver use that code. Because the SMS driver ends
up having a UICC client anyway, so all this intra-driver communication
is really there to save two response decoder functions being
copy-pasted, no? Not worth the trouble.
> /* Returns file info */
> static gboolean fake_file_info(gpointer user)
> @@ -89,6 +540,286 @@ static gboolean fake_file_info(gpointer user)
> return FALSE;
> }
>
> +static gboolean check_response_status_with_cause(const GIsiMessage *msg,
> + uint8_t msgid,
> + uint8_t service,
> + int cause,
> + int pos)
> +{
> + uint8_t type;
> + uint8_t msg_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, &msg_cause) ||
> + msg_cause != 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;
> +}
> +
> +static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
> + uint8_t service)
> +{
> + int cause, pos;
> +
> + if (g_isi_msg_version_major(msg) == 6 &&
> + g_isi_msg_version_minor(msg) >= 0) {
> + cause = UICC_STATUS_OK;
> + pos = 0;
> + } else {
> + cause = SIM_SERV_OK;
> + pos = 1;
> + }
> +
> + return check_response_status_with_cause(msg, msgid, service, cause,
> + pos);
> +}
> +
> +
> +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;
> +
> +
> + if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
> + return;
> +
> + if (fcp != FCP_TEMPLATE)
> + return;
> +
> + if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
> + return;
> +
> + while (read < fcp_len) {
> + if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
> + return;
> + if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
> + return;
> +
> + 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 read_file_data *fdata = cbd->user;
> + struct file_info const *info;
> + GIsiSubBlockIter iter;
> + struct sim_data *sd = NULL;
> + uint8_t sbcount = 0;
> +
> + if (fdata != NULL) {
> + sd = fdata->sim_data;
> + info = fdata->info;
> + g_free(cbd->user);
> + cbd->user = NULL;
> + }
> +
> + if (sd == NULL)
> + goto error;
> +
> + 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);
This is reading three different bytes into access[0].
> + (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)
> {
> @@ -98,276 +829,1700 @@ static void isi_read_file_info(struct ofono_sim *sim, int fileid,
> { 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;
>
> - 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);
> + 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;
> + struct read_file_data *fdata = g_try_malloc0(sizeof(
> + struct read_file_data));
> +
> + 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);
> +
> + fdata->sim_data = sd;
> +
> + for (i = 0; i < N; i++) {
> + if (fileid == static_file_info[i].fileid &&
> + cbd != NULL) {
> + fdata->info = (struct file_info *)
> + &static_file_info[i];
> + continue;
> + }
> + }
> + cbd->user = (void *) fdata;
Why go through all this trouble of searching for static file access
data before the response arrives? Why not simply do the lookup for the
access bytes in the response callback, and save all this trouble of
mallocing a second level of user data? The fileid is available in the
response messages, no?
> + 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,
> + /* Elementary file short id*/
> + fileid_to_short_fileid(fileid),
> + 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;
> + }
> + }
I think this is a fine example why the UICC code doesn't belong in
this file. The original SIM driver is mostly a reverse abstraction of
a high-level API, whereas PN_UICC has more appropriate support for EF
access. These blocks of code have absolutely nothing in common, no
message decoding to share, etc.
They belong in separate files for sure.
> + }
> +error:
> 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)
> +static void spn_resp_cb(const GIsiMessage *msg, void *data)
> {
> - uint8_t type;
> - uint8_t cause;
> + struct isi_cb_data *cbd = data;
> + ofono_sim_read_cb_t cb = cbd->cb;
>
> - if (g_isi_msg_error(msg) < 0) {
> - DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
> - return FALSE;
> - }
> + const struct sim_spn *resp = NULL;
> + size_t len = sizeof(struct sim_spn);
>
> - if (g_isi_msg_id(msg) != msgid) {
> - DBG("Unexpected msg: %s",
> - sim_message_id_name(g_isi_msg_id(msg)));
> - return FALSE;
> - }
> + uint8_t spn[SIM_MAX_SPN_LENGTH + 1];
> + int i;
>
> - 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 (!check_response_status(msg, SIM_SERV_PROV_NAME_RESP,
> + SIM_ST_READ_SERV_PROV_NAME))
> + goto error;
>
> - if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
> - DBG("Unexpected service: 0x%02X", type);
> - return FALSE;
> + if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
> + goto error;
> +
> + /* Set display condition bits */
> + spn[0] = (resp->disp_home & 0x01) | ((resp->disp_roam & 0x01) << 1);
> +
> + /* Convert from a NULL-terminated UCS-2 string to ASCII */
> + for (i = 0; i < SIM_MAX_SPN_LENGTH; i++) {
> + uint16_t c = resp->name[i] >> 8 | resp->name[i] << 8;
> +
> + if (c == 0)
> + c = 0xFF;
> + else if (!g_ascii_isprint(c))
> + c = '?';
> +
> + spn[i + 1] = c;
> }
> - return TRUE;
> +
> + CALLBACK_WITH_SUCCESS(cb, spn, sizeof(spn), cbd->data);
> + return;
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> }
>
> -static void spn_resp_cb(const GIsiMessage *msg, void *data)
> +static gboolean isi_read_spn(struct ofono_sim *sim, struct isi_cb_data *cbd)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + const uint8_t msg[] = {
> + SIM_SERV_PROV_NAME_REQ,
> + SIM_ST_READ_SERV_PROV_NAME,
> + 0
> + };
> +
> + if (sd == NULL)
> + return FALSE;
> +
> + return g_isi_client_send(sd->client, msg, sizeof(msg),
> + spn_resp_cb, cbd, g_free);
> +}
> +
> +static void read_iccid_resp_cb(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_read_cb_t cb = cbd->cb;
> + struct sim_iccid *icc;
> + size_t len = sizeof(struct sim_iccid);
> +
> + if (!check_response_status(msg, SIM_READ_FIELD_RESP, ICC))
> + goto error;
> +
> + if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &icc, len))
> + goto error;
> +
> + CALLBACK_WITH_SUCCESS(cb, icc->id, 10, cbd->data);
> + return;
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> +}
> +
> +static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + const uint8_t req[] = {
> + SIM_READ_FIELD_REQ,
> + ICC,
> + };
> +
> + if (sd == NULL)
> + return FALSE;
> +
> + return g_isi_client_send(sd->client, req, sizeof(req),
> + 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 || sd == NULL)
> + goto error;
> +
> + 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,
> + /*Elementary file short id*/
> + fileid_to_short_fileid(fileid),
> + 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;
> +
> + } else {
> + switch (fileid) {
> + case SIM_EFSPN_FILEID:
> + done = isi_read_spn(sim, cbd);
> + break;
> +
> + case SIM_EF_ICCID_FILEID:
> + done = isi_read_iccid(sim, cbd);
> + break;
> +
> + default:
> + done = FALSE;
> + }
> +
> + if (done)
> + return;
> + }
> +
> + DBG("Fileid %04X not implemented", fileid);
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
> + g_free(cbd);
> +}
> +
> +static void isi_read_file_linear_fixed_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_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);
You're memmove():ing a static buffer of up to 2M bytes (filelen is a
32bit integer) into a static buffer 256 bytes long. That's not right.
There is a g_isi_sb_iter_get_struct() that we generally use in
situations like this, which among other things avoids useless copying
of bytes around in the stack.
> + 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,
> + /* Elementary file short file id*/
> + fileid_to_short_fileid(fileid),
> + 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,
> + int record, int length,
> + ofono_sim_read_cb_t cb, void *data)
> +{
> + DBG("Fileid %04X not implemented", fileid);
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
> +}
> +
> +static void isi_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("Fileid %04X not implemented", 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,
> + fileid_to_short_fileid(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,
> + int length, const unsigned char *value,
> + ofono_sim_write_cb_t cb, void *data)
> +{
> + DBG("Fileid %04X not implemented", fileid);
> + CALLBACK_WITH_FAILURE(cb, 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 = 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;
> + size_t len = sizeof(struct sim_imsi);
> +
> + char imsi[SIM_MAX_IMSI_LENGTH + 1];
> + size_t i, j;
> +
> + if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
> + goto error;
> +
> + /* Ignore the low-order semi-octet of the first byte */
> + imsi[0] = ((resp->imsi[0] & 0xF0) >> 4) + '0';
> +
> + for (i = 1, j = 1; i < resp->length && j < SIM_MAX_IMSI_LENGTH; i++) {
> + char nibble;
> +
> + imsi[j++] = (resp->imsi[i] & 0x0F) + '0';
> + nibble = (resp->imsi[i] & 0xF0) >> 4;
> + if (nibble != 0x0F)
> + imsi[j++] = nibble + '0';
> + }
> +
> + imsi[j] = '\0';
> + CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
> + return;
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
> +}
> +
> +static void isi_read_imsi(struct ofono_sim *sim,
> + ofono_sim_imsi_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);
> + size_t len;
> +
> + const uint8_t msg[] = {
> + SIM_IMSI_REQ_READ_IMSI,
> + READ_IMSI
> + };
> +
> + 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;
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, data);
> + g_free(cbd);
> +}
> +
> +static void uicc_application_activate_req(GIsiClient *client,
> + void *opaque,
> + unsigned char appl_type,
> + unsigned char aid);
> +
> +
> +static void uicc_application_activate_resp(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_sim *sim = data;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> + uint8_t status;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + if (g_isi_msg_error(msg) < 0)
> + return;
> +
> + if (g_isi_msg_id(msg) != UICC_APPLICATION_RESP)
> + return;
> +
> + g_isi_msg_data_get_byte(msg, 1, &status);
> +
> + if (status == UICC_STATUS_OK || status == 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(sd->sim_application_list_p);
> + }
> + } else {
> + int i = sim_applications_get_next_index(
> + sd->sim_application_list_p,
> + sd->trying_app_id);
> +
> + if (i == NOT_AVAILABLE) {
> + g_free(sd->sim_application_list_p);
> + return;
> + }
> +
> + DBG("Activation Error, trying to activate APP with ID:%d", i);
> + uicc_application_activate_req(sd->client, sim,
> + sd->sim_application_list_p->app_type[i],
> + sd->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)) {
Might as well have a for loop here, like elsewhere in the drivers.
> + 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);
Not checking the return value is one thing, but how is the (void)
supposed to help here?
> + 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*/
Hmm.. Maybe a macro for all of these 16bit identifiers and byte order
conversions?
> + 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;
This returns if the request did *not* fail?
> + everything_ok = FALSE;
> + }
> +
> + sd->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);
> +
> + sd->sim_application_list_p->app_list[appl_id] =
> + appl_id;
> + sd->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(
> + sd->sim_application_list_p,
> + NOT_ACTIVATED);
> +
> + if (index != NOT_AVAILABLE) {
> + DBG("Activating APP index:%d", index);
> + sd->trying_app_id =
> + sd->sim_application_list_p->app_list[index];
> + sd->trying_app_type =
> + sd->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,
> + sd->sim_application_list_p->app_type[index],
> + sd->sim_application_list_p->app_list[index]);
> + } else
> + g_free(sd->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;
> + GIsiSubBlockIter iter;
> + struct sim_data *sd =
> + ofono_sim_get_data((struct ofono_sim *) local_sim);
> + uint8_t sbcount = 0;
> +
> + if (g_isi_msg_error(msg) < 0)
> + goto error;
> +
> + if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_VERIFY)) {
> + sd->passwd_required = FALSE;
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + goto out;
> + }
> +
> + 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 UICC_PIN_STATUS_AUTH_BLOCKED:
> + case UICC_PIN_STATUS_AUTH_FAILED:
> + DBG("Authentication method blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + break;
> + default:
> +
> + if ((status & 0xfff0) ==
> + UICC_PIN_STATUS_AUTH_RETRIES)
> + DBG("Attempts left %d", status & 0xf);
> +
> + break;
> + }
> +
> + break;
> + }
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> +out:
> + g_free(cbd);
> +}
> +
> +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);
> + char pin[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Writing '= { 0 }' is the same thing
> +
> + sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
> +
> + 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 */
> + };
> + struct iovec iov[2] = {
> + { msg, sizeof(msg) },
> + { pin, 8 }
> + };
> +
> + if ((pinlen < 4) || (pinlen > 8))
> + goto error;
> +
> + memmove(pin, passwd, pinlen);
> +
> + g_isi_client_vsend_with_timeout(sd->client, iov, 2,
> + SIM_TIMEOUT, uicc_pin_enter_resp, cbd,
> + g_free);
> + return;
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> +}
> +
> +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_pin_prompt_resp(const GIsiMessage *msg, void *data)
> {
> struct isi_cb_data *cbd = data;
> - ofono_sim_read_cb_t cb = cbd->cb;
> + 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)) {
> +
> + if (!check_response_status_with_cause(msg, UICC_PIN_RESP,
> + UICC_PIN_PROMPT_VERIFY,
> + UICC_STATUS_PIN_DISABLED, 1))
> + goto error;
> + }
My brain doesn't have a powerful enough logic unit to be able to parse this. ;)
>
> - const struct sim_spn *resp = NULL;
> - size_t len = sizeof(struct sim_spn);
> + g_isi_msg_data_get_byte(msg, 1, &status);
> +
> + if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
> + sd->pin_state_received = TRUE;
> + } else if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_INFO)) {
...especially after this.
> + 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);
> + }
> + }
>
> - uint8_t spn[SIM_MAX_SPN_LENGTH + 1];
> - int i;
> + 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);
> + }
>
> - if (!check_response_status(msg, SIM_SERV_PROV_NAME_RESP,
> - SIM_ST_READ_SERV_PROV_NAME))
> - goto error;
> + 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 (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
> - goto error;
> + if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
...and this.
> + uicc_pin_prompt(cbd->user,
> + OFONO_SIM_PASSWORD_SIM_PIN,
> + cb,
> + cbd->data,
> + UICC_PIN_INFO);
> + }
>
> - /* Set display condition bits */
> - spn[0] = (resp->disp_home & 0x01) | ((resp->disp_roam & 0x01) << 1);
> + CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
> + return;
> +error:
> + DBG("PIN prompt verify failed");
> + CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
> +}
>
> - /* Convert from a NULL-terminated UCS-2 string to ASCII */
> - for (i = 0; i < SIM_MAX_SPN_LENGTH; i++) {
> - uint16_t c = resp->name[i] >> 8 | resp->name[i] << 8;
> +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;
> + unsigned char msg[] = {
> + UICC_PIN_REQ,
> + service,
> + 0, /*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,
> + 0, /*PIN ID*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0 /*Filler*/
> + };
>
> - if (c == 0)
> - c = 0xFF;
> - else if (!g_ascii_isprint(c))
> - c = '?';
> + sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
>
> - spn[i + 1] = c;
> + if (cbd == NULL || sd == NULL) {
> + CALLBACK_WITH_FAILURE(cb, -1, data);
> + g_free(cbd);
> + return;
> }
>
> - CALLBACK_WITH_SUCCESS(cb, spn, sizeof(spn), cbd->data);
> - return;
> + if (sd->current_pin_id == 0) {
> + CALLBACK_WITH_FAILURE(cb, -1, data);
> + g_free(cbd);
> + return;
> + }
>
> -error:
> - CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> + msg[2] = sd->app_id;
> + msg[11] = sd->current_pin_id;
> +
> + g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
> + SIM_TIMEOUT, uicc_pin_prompt_resp,
> + cbd, g_free);
> }
>
> -static gboolean isi_read_spn(struct ofono_sim *sim, struct isi_cb_data *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;
>
> - const uint8_t msg[] = {
> - SIM_SERV_PROV_NAME_REQ,
> - SIM_ST_READ_SERV_PROV_NAME,
> - 0
> - };
> + if (sd->pin_state_received) {
> + int lock_type = OFONO_SIM_PASSWORD_NONE;
>
> - if (sd == NULL)
> - return FALSE;
> + 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;
>
> - return g_isi_client_send(sd->client, msg, sizeof(msg),
> - spn_resp_cb, cbd, g_free);
> + 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, OFONO_SIM_PASSWORD_SIM_PIN,
> + cb, data, UICC_PIN_PROMPT_VERIFY);
> + return;
> + }
> +
> + DBG("No UICC_PIN_IND received");
> + CALLBACK_WITH_FAILURE(cb, -1, data);
> + }
> }
>
> -static void read_iccid_resp_cb(const GIsiMessage *msg, void *data)
> +static void uicc_pin_enable_resp(const GIsiMessage *msg, void *data)
> {
> struct isi_cb_data *cbd = data;
> - ofono_sim_read_cb_t cb = cbd->cb;
> - struct sim_iccid *icc;
> - size_t len = sizeof(struct sim_iccid);
> + 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);
>
> - if (!check_response_status(msg, SIM_READ_FIELD_RESP, ICC))
> - goto error;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
>
> - if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &icc, len))
> + if (g_isi_msg_error(msg) < 0)
> goto error;
>
> - CALLBACK_WITH_SUCCESS(cb, icc->id, 10, cbd->data);
> - return;
> -
> -error:
> - CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> -}
> + if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_DISABLE) &&
> + !check_response_status(msg, UICC_PIN_RESP,
> + UICC_PIN_ENABLE))
> + goto cont;
>
> -static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
> -{
> - struct sim_data *sd = ofono_sim_get_data(sim);
> + DBG("PIN lock/unlock succeeded");
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
>
> - const uint8_t req[] = {
> - SIM_READ_FIELD_REQ,
> - ICC,
> - };
> +cont:
> + 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 UICC_PIN_STATUS_AUTH_BLOCKED:
> + case UICC_PIN_STATUS_AUTH_FAILED:
> + DBG("Authentication method blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + break;
> + default:
> +
> + if ((status & 0xfff0) ==
> + UICC_PIN_STATUS_AUTH_RETRIES)
> + DBG("Attempts left %d", status & 0xf);
> +
> + break;
> + }
> + }
> + default:
> + break;
> + }
>
> - if (sd == NULL)
> - return FALSE;
> + g_isi_sb_iter_next(&iter);
> + }
>
> - return g_isi_client_send(sd->client, req, sizeof(req),
> - read_iccid_resp_cb, cbd, g_free);
> +error:
> + DBG("PIN lock/unlock failed");
> + CALLBACK_WITH_FAILURE(cb, 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)
> +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 isi_cb_data *cbd;
> - gboolean done;
> + 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;
>
> - 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;
> -
> - case SIM_EF_ICCID_FILEID:
> - done = isi_read_iccid(sim, cbd);
> - break;
> + sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
>
> - default:
> - done = FALSE;
> - }
> + if (sd->current_pin_id == 0)
> + goto error;
>
> - if (done)
> + if (enable)
> + service = UICC_PIN_ENABLE;
> + else
> + 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;
> -
> - DBG("Fileid %04X not implemented", fileid);
> + }
>
> error:
> - CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
> + CALLBACK_WITH_FAILURE(cb, data);
> g_free(cbd);
> + return;
> }
>
> -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 uicc_pin_change_resp(const GIsiMessage *msg, void *data)
> {
> - DBG("Fileid %04X not implemented", fileid);
> - CALLBACK_WITH_FAILURE(cb, NULL, 0, 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);
>
> -static void isi_read_file_cyclic(struct ofono_sim *sim, int fileid,
> - int record, int length,
> - ofono_sim_read_cb_t cb, void *data)
> -{
> - DBG("Fileid %04X not implemented", fileid);
> - CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
> -}
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
>
> -static void isi_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("Fileid %04X not implemented", fileid);
> - CALLBACK_WITH_FAILURE(cb, data);
> -}
> + if (g_isi_msg_error(msg) < 0)
> + goto error;
>
> -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)
> -{
> - DBG("Fileid %04X not implemented", fileid);
> - CALLBACK_WITH_FAILURE(cb, data);
> + if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_CHANGE))
> + goto cont;
> +
> + DBG("PIN change succeeded");
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
> +
> +cont:
> + 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 UICC_PIN_STATUS_AUTH_BLOCKED:
> + case UICC_PIN_STATUS_AUTH_FAILED:
> + DBG("Authentication method blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + break;
> + default:
> +
> + if ((status & 0xfff0) ==
> + UICC_PIN_STATUS_AUTH_RETRIES)
> + DBG("Attempts left %d", status & 0xf);
> +
> + break;
> + }
> +
> + break;
> + }
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +error:
> + DBG("PIN change failed");
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> }
>
> -static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
> - int length, const unsigned char *value,
> - ofono_sim_write_cb_t cb, void *data)
> +static void uicc_change_pin(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("Fileid %04X not implemented", fileid);
> + 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("old=%s, new=%s, PINID=%02x",
> + old, new, sd->current_pin_id);
> +
> + if ((cbd) && (sd) && (sd->current_pin_id)) {
> + unsigned char service = UICC_PIN_CHANGE;
> + unsigned char oldlen = strlen(old);
> + unsigned char newlen = strlen(new);
> +
> + unsigned char msg[] = {
> + UICC_PIN_REQ,
> + service,
> + sd->app_id,
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 2, /*number of subblocks*/
> + /* Subblock 1 */
> + UICC_SB_PIN >> 8,
> + UICC_SB_PIN & 0xff,
> + 0,
> + 16, /* Must be fixed */
> + sd->current_pin_id, /* PIN id */
> + UICC_PIN_OLD, /* PIN qualifier */
> + oldlen, /* PIN length */
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + /* Subblock 2 */
> + UICC_SB_PIN >> 8,
> + UICC_SB_PIN & 0xff,
> + 0,
> + /* Sub block length:
> + * "header" size + 1 (=trailing filler) + PIN length */
> + 16,
> + sd->current_pin_id, /* PIN id */
> + UICC_PIN_NEW, /* PIN qualifier */
> + newlen, /* PIN length */
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0
> + };
> +
> + if ((oldlen < 4) || (oldlen > 8))
> + goto error;
> +
> + if ((newlen < 4) || (newlen > 8))
> + goto error;
> +
> + memmove(&msg[14], old, oldlen);
> + memmove(&msg[30], new, newlen);
> + g_isi_client_send_with_timeout(
> + sd->client, msg, sizeof(msg), SIM_TIMEOUT,
> + uicc_pin_change_resp, cbd, g_free);
> + return;
> + }
> +
> +error:
> + DBG("Error");
> CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> + return;
> }
>
> -static void imsi_resp_cb(const GIsiMessage *msg, void *data)
> +static void uicc_pin_send_puk_resp(const GIsiMessage *msg, void *data)
> {
> struct isi_cb_data *cbd = data;
> - ofono_sim_imsi_cb_t cb = cbd->cb;
> + ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> + struct ofono_sim_local *local_sim =
> + (struct ofono_sim_local *) cbd->user;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
>
> - struct sim_imsi *resp;
> - size_t len = sizeof(struct sim_imsi);
> + if (g_isi_msg_error(msg) < 0)
> + goto error;
> + if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_UNBLOCK))
> + goto cont;
> +
> + DBG("PIN reset succeeded");
> + /* Only PIN1 can be reseted, turns PIN query on */
> + local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
> + local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PUK] = FALSE;
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
>
> - char imsi[SIM_MAX_IMSI_LENGTH + 1];
> - size_t i, j;
> +cont:
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
>
> - if (!check_response_status(msg, SIM_IMSI_RESP_READ_IMSI, READ_IMSI))
> - goto error;
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
>
> - if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
> - goto error;
> + 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);
>
> - /* Ignore the low-order semi-octet of the first byte */
> - imsi[0] = ((resp->imsi[0] & 0xF0) >> 4) + '0';
> + switch (status) {
> + case UICC_PIN_STATUS_AUTH_BLOCKED:
> + case UICC_PIN_STATUS_AUTH_FAILED:
> + DBG("Authentication method blocked");
> + break;
> + default:
>
> - for (i = 1, j = 1; i < resp->length && j < SIM_MAX_IMSI_LENGTH; i++) {
> - char nibble;
> + if ((status & 0xfff0) ==
> + UICC_PIN_STATUS_AUTH_RETRIES)
> + DBG("Attempts left %d", status & 0xf);
>
> - imsi[j++] = (resp->imsi[i] & 0x0F) + '0';
> - nibble = (resp->imsi[i] & 0xF0) >> 4;
> - if (nibble != 0x0F)
> - imsi[j++] = nibble + '0';
> - }
> + break;
> + }
>
> - imsi[j] = '\0';
> - CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
> - return;
> + break;
> + }
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
>
> error:
> - CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
> + DBG("PIN reset failed");
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> }
>
> -static void isi_read_imsi(struct ofono_sim *sim,
> - ofono_sim_imsi_cb_t cb, void *data)
> +static void uicc_pin_send_puk(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);
> + unsigned char service = UICC_PIN_UNBLOCK;
> + unsigned char pinlen = strlen(passwd);
> + uint8_t pin[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
> + uint8_t pukcode[10] = { 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0 };
> +
> + uint8_t msg[] = {
> + UICC_PIN_REQ,
> + service,
> + sd->app_id,
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 2, /*number of subblocks*/
> + /* Subblock 1*/
> + UICC_SB_PIN >> 8,
> + UICC_SB_PIN & 0xff,
> + 0,
> + 16, /*sb length, must be fixed*/
> + sd->current_pin_id, /* PIN id*/
> + UICC_PIN_NEW, /* PIN qualifier*/
> + pinlen /* PIN length*/
> + };
> + uint8_t msg2[] = {
> + /* Subblock 2*/
> + UICC_SB_PUK >> 8,
> + UICC_SB_PUK & 0xff,
> + 0,
> + 16, /*Sub block length*/
> + sd->current_pin_id, /* PIN id*/
> + 8, /* PUK length*/
> + };
>
> - const uint8_t msg[] = {
> - SIM_IMSI_REQ_READ_IMSI,
> - READ_IMSI
> + struct iovec iov[4] = {
> + { msg, sizeof(msg) },
> + { pin, 8 },
> + { msg2, sizeof(msg2) },
> + { pukcode, 10 }
> };
> - size_t len = sizeof(msg);
>
> if (cbd == NULL || sd == NULL)
> goto error;
>
> - if (g_isi_client_send(sd->client, msg, len, imsi_resp_cb, cbd, g_free))
> - return;
> + if ((pinlen < 4) || (pinlen > 8))
> + goto error;
> +
> + if (strlen(puk) != 8)
> + goto error;
> +
> + sd->current_pin_id = sd->pin1_id; /* No way to reset PIN2 */
> +
> + memmove(pin, passwd, pinlen);
> + memmove(pukcode, puk, 8);
> +
> + g_isi_client_vsend_with_timeout(sd->client, iov, 4, SIM_TIMEOUT,
> + uicc_pin_send_puk_resp, cbd,
> + g_free);
> + return;
>
> error:
> - CALLBACK_WITH_FAILURE(cb, NULL, data);
> + CALLBACK_WITH_FAILURE(cb, data);
> g_free(cbd);
> + return;
> }
>
> static void isi_sim_register(struct ofono_sim *sim)
> @@ -414,34 +2569,125 @@ static void sim_ind_cb(const GIsiMessage *msg, void *data)
> struct sim_data *sd = ofono_sim_get_data(sim);
> uint8_t status;
>
> - if (sd == NULL || g_isi_msg_id(msg) != SIM_IND || sd->registered)
> - return;
> + if (g_isi_client_resource(sd->client) == PN_UICC) {
> + uint8_t service_type;
> + uint8_t pin_id;
> +
> + g_isi_msg_data_get_byte(msg, 0, &service_type);
> + g_isi_msg_data_get_byte(msg, 1, &pin_id);
> +
> + switch (g_isi_msg_id(msg)) {
> +
> + case UICC_CARD_IND:
> + ofono_sim_inserted_notify(sim, TRUE);
> +
> + if ((service_type == UICC_CARD_READY) &&
> + (!sd->uicc_app_started)) {
> + DBG("UICC_CARD_IND activation");
> + uicc_application_list_req(sd->client, sim);
> + }
> + break;
> + case UICC_PIN_IND:
> + sd->pin_state_received = TRUE;
> + sd->passwd_required = FALSE;
> +
> + switch (service_type) {
> + case UICC_PIN_VERIFY_NEEDED:
> + update_locked_pin((
> + struct ofono_sim_local *)sim,
> + UICC_PIN_VERIFY_NEEDED,
> + pin_id);
> + break;
> + case UICC_PIN_UNBLOCK_NEEDED:
> + update_locked_pin((
> + struct ofono_sim_local *)sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + pin_id);
> + break;
> + case UICC_PIN_PERMANENTLY_BLOCKED:
> + case UICC_PIN_VERIFIED:
> + default:
> + break;
> + }
> +
> + break;
> + case UICC_IND:
> + DBG("UICC IND RECEIVED");
> +
> + if (service_type == UICC_START_UP_COMPLETE)
> + sd->passwd_required = FALSE;
> +
> + break;
> + default:
> + break;
> + }
> + } else {
> + if (sd == NULL || g_isi_msg_id(msg) != SIM_IND ||
> + sd->registered)
> + return;
> +
> + if (!g_isi_msg_data_get_byte(msg, 0, &status))
> + return;
> +
> + switch (status) {
> + case SIM_ST_PIN:
> + isi_sim_register(sim);
> + break;
> +
> + case SIM_ST_INFO:
> + isi_read_hplmn(sim);
> + break;
> + }
> + }
> +}
> +
> +static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_sim *sim = data;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + GIsiModem *modem = g_isi_client_modem(sd->primary);
>
> - if (!g_isi_msg_data_get_byte(msg, 0, &status))
> + if (g_isi_msg_error(msg) < 0)
> return;
>
> - switch (status) {
> - case SIM_ST_PIN:
> - isi_sim_register(sim);
> - break;
> + ISI_VERSION_DBG(msg);
>
> - case SIM_ST_INFO:
> - isi_read_hplmn(sim);
> - break;
> + sd->client = sd->primary;
> + sd->uicc_app_started = FALSE;
> + sd->pin_state_received = FALSE;
> + sd->passwd_required = TRUE;
> + sd->current_pin_id = 0x01;
> + sd->pin1_id = 0x01;
> + sd->pin2_id = 0x81;
> +
> + g_isi_modem_set_sim(modem, sim);
> +
> + if (!sd->uicc_app_started) {
> + DBG("Let's check if we have UICC applications");
> + uicc_application_list_req(sd->client, sim);
> }
> + g_isi_client_destroy(sd->secondary);
> }
>
> static void sim_reachable_cb(const GIsiMessage *msg, void *data)
> {
> struct ofono_sim *sim = data;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + GIsiModem *modem = g_isi_client_modem(sd->secondary);
>
> if (g_isi_msg_error(msg) < 0)
> return;
>
> ISI_VERSION_DBG(msg);
>
> + sd->client = sd->secondary;
> +
> + g_isi_modem_set_sim(modem, sim);
> +
> /* Check if SIM is ready by reading HPLMN */
> isi_read_hplmn(sim);
> +
> + g_isi_client_destroy(sd->primary);
> }
>
> static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
> @@ -454,16 +2700,32 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
> if (sd == NULL)
> return -ENOMEM;
>
> - sd->client = g_isi_client_create(modem, PN_SIM);
> - if (sd->client == NULL) {
> + sd->primary = g_isi_client_create(modem, PN_UICC);
> +
> + if (sd->primary == NULL) {
> + g_free(sd);
> + return -ENOMEM;
> + }
> +
> + sd->secondary = g_isi_client_create(modem, PN_SIM);
> +
> + if (sd->secondary == NULL) {
> g_free(sd);
> return -ENOMEM;
> }
>
> ofono_sim_set_data(sim, sd);
>
> - g_isi_client_ind_subscribe(sd->client, SIM_IND, sim_ind_cb, sim);
> - g_isi_client_verify(sd->client, sim_reachable_cb, sim, NULL);
> + g_isi_client_ind_subscribe(sd->secondary, SIM_IND, sim_ind_cb, sim);
> +
> + g_isi_client_ind_subscribe(sd->primary, UICC_IND, sim_ind_cb, sim);
> + g_isi_client_ind_subscribe(sd->primary, UICC_CARD_IND, sim_ind_cb, sim);
> + g_isi_client_ind_subscribe(sd->primary, UICC_PIN_IND, sim_ind_cb, sim);
> + g_isi_client_ind_subscribe(sd->primary, UICC_APPLICATION_IND,
> + sim_ind_cb, sim);
> +
> + g_isi_client_verify(sd->primary, uicc_reachable_cb, sim, NULL);
> + g_isi_client_verify(sd->secondary, sim_reachable_cb, sim, NULL);
>
> return 0;
> }
> @@ -471,13 +2733,23 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
> static void isi_sim_remove(struct ofono_sim *sim)
> {
> struct sim_data *data = ofono_sim_get_data(sim);
> -
> - ofono_sim_set_data(sim, NULL);
> + GIsiModem *modem = g_isi_client_modem(data->client);
>
> if (data == NULL)
> return;
>
> - g_isi_client_destroy(data->client);
> + g_isi_modem_set_sim(modem, NULL);
> +
> + if (g_isi_client_resource(data->client) == PN_UICC) {
> + data->uicc_app_started = FALSE;
> + data->pin_state_received = FALSE;
> + data->passwd_required = TRUE;
> +
> + g_isi_client_destroy(data->client);
> + } else
> + g_isi_client_destroy(data->client);
> +
> + ofono_sim_set_data(sim, NULL);
> g_free(data);
> }
>
> @@ -493,8 +2765,18 @@ 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 = uicc_passwd_state_query,
> + .send_passwd = uicc_pin_enter,
> + .reset_passwd = uicc_pin_send_puk,
> + .change_passwd = uicc_change_pin,
> + .lock = uicc_pin_enable,
Here is another example why having UICC in this file is a bad idea.
Obviously, a modem without PN_UICC would not work correctly here.
I can take this patch, and push a refactored version of the code as a
separate uicc.c file that implements a "wgmodem2.5" SIM driver. That
is the most sensible way forward, I think. Unless you'd like to do
this work, and I think it is quite a bit of work still.
Those parts touching SIM atom private data are a different thing. We
really need to figure out what is happening there, and have a proper
solution.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 04/18] plugins: add u8500 to udev
2011-02-23 11:43 ` [PATCH v2 04/18] plugins: add u8500 to udev Andreas Westin
@ 2011-02-25 15:40 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-25 15:40 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 310 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> plugins/ofono.rules | 3 +++
> plugins/udev.c | 2 ++
> 2 files changed, 5 insertions(+), 0 deletions(-)
Patch applied. Thanks!
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 06/18] src: add missing SIM enum to simutil.h
2011-02-23 11:43 ` [PATCH v2 06/18] src: add missing SIM enum to simutil.h Andreas Westin
@ 2011-02-25 15:41 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-25 15:41 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 298 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> src/simutil.h | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
Applied this patch with minor tweak of the commit message.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5
2011-02-23 11:43 ` [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5 Andreas Westin
@ 2011-02-25 15:41 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-25 15:41 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 553 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> Makefile.am | 4 +-
> drivers/isimodem/debug.c | 84 +++++++++++++++
> drivers/isimodem/debug.h | 1 +
> drivers/isimodem/uicc.h | 265 ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 353 insertions(+), 1 deletions(-)
> create mode 100644 drivers/isimodem/uicc.h
I applied this patch, but removed the inter-driver API for now.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5
2011-02-23 11:43 ` [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5 Andreas Westin
@ 2011-02-25 15:41 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-02-25 15:41 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 435 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/debug.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/isimodem/debug.h | 1 +
> drivers/isimodem/sms.h | 34 ++++++++++++++++++++++++++++
> 3 files changed, 91 insertions(+), 0 deletions(-)
Patch has been pushed. Thanks!
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5
2011-02-23 11:43 ` [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
@ 2011-03-03 15:45 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 15:45 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 968 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/call-settings.c | 711 +++++++++++++++++++++++++++++++++++++-
> drivers/isimodem/call.h | 9 +
> drivers/isimodem/debug.c | 4 +
> drivers/isimodem/ss.h | 22 ++
> 4 files changed, 728 insertions(+), 18 deletions(-)
I pushed CLIP, COLP and COLR query support based on this patch, plus
refactored the call waiting code some.
The CLIR query and set functionality included was sufficiently
convoluted that I had to leave it out for the time being.
Frankly, I am not sure that even oFono core is working properly here,
if the CLIR status can only be modified locally. That said, my
supplementary-service-foo is admittedly lacking, so if someone can
make sense of CLIR here, I would appreciate comments and/or patches.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD
2011-02-23 11:43 ` [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
@ 2011-03-03 15:45 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 15:45 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 416 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/ussd.c | 36 ++++++++++++++++++++++++++++++------
> 1 files changed, 30 insertions(+), 6 deletions(-)
Patch has been pushed, with some refactoring done afterwards. The N900
modem handles padding fine, so might as well use it always.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall
2011-02-23 11:43 ` [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
@ 2011-03-03 15:45 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 15:45 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 425 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/call.h | 82 ++++++++++++++++-
> drivers/isimodem/voicecall.c | 218 +++++++++++++++++++++++++++++++++---------
> 2 files changed, 253 insertions(+), 47 deletions(-)
Patch was applied with some refactoring done afterwards. Thanks.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added
2011-02-23 11:43 ` [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
@ 2011-03-03 15:46 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 15:46 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 379 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> SS_GSM_BSC_INFO added.
> ---
> drivers/isimodem/call-barring.c | 99 ++++++++++++++++++++++++++++++++++----
> 1 files changed, 88 insertions(+), 11 deletions(-)
Patch was applied, with some refactoring done afterwards.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn
2011-02-23 11:43 ` [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
@ 2011-03-03 15:46 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 15:46 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 424 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/call-forwarding.c | 1 -
> drivers/isimodem/ssn.c | 406 +++++++++++++++++++++++++++++++++++-
> 2 files changed, 401 insertions(+), 6 deletions(-)
I applied this patch, but had to do some heavy refactoring afterwards.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding
2011-02-23 11:43 ` [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
@ 2011-03-03 16:36 ` Aki Niemi
0 siblings, 0 replies; 32+ messages in thread
From: Aki Niemi @ 2011-03-03 16:36 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 353 bytes --]
Hi,
2011/2/23 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/call-forwarding.c | 29 +++++++++++++++++++++++++----
> 1 files changed, 25 insertions(+), 4 deletions(-)
Patch has been applied. Some refactoring after the fact, though.
Cheers,
Aki
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2011-03-03 16:36 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-23 11:43 [PATCH v2 00/18] wgmodem2.5 support Andreas Westin
2011-02-23 11:43 ` [PATCH v2 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 02/18] isimodem: added codepoints for u8500 Andreas Westin
2011-02-23 13:17 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 03/18] plugins: add plugin " Andreas Westin
2011-02-23 13:26 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 04/18] plugins: add u8500 to udev Andreas Westin
2011-02-25 15:40 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 05/18] gisi: add getter and setter for sim Andreas Westin
2011-02-23 11:43 ` [PATCH v2 06/18] src: add missing SIM enum to simutil.h Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 07/18] isimodem: code points uicc sim wgmodem2.5 Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
2011-02-25 15:20 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 11/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
2011-03-03 15:45 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 12/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
2011-03-03 15:46 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 13/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
2011-03-03 16:36 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 14/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
2011-03-03 15:46 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 15/18] isimodem: code points for sms wgmodem2.5 Andreas Westin
2011-02-25 15:41 ` Aki Niemi
2011-02-23 11:43 ` [PATCH v2 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
2011-02-23 11:43 ` [PATCH v2 18/18] isimodem: initial support for UICC phonebook Andreas Westin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox