* [PATCH 01/18] gisi: pipe and pep for wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
@ 2011-02-15 12:30 ` Andreas Westin
2011-02-15 13:23 ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2011-02-15 12:30 ` [PATCH 02/18] gisi: modem version detection Andreas Westin
` (16 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:30 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] 38+ messages in thread* [PATCH 02/18] gisi: modem version detection
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
2011-02-15 12:30 ` [PATCH 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
@ 2011-02-15 12:30 ` Andreas Westin
2011-02-15 12:30 ` [PATCH 03/18] isimodem: general build updates for wgmodem2.5 Andreas Westin
` (15 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1817 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
gisi/modem.c | 27 +++++++++++++++++++++++++++
gisi/modem.h | 6 ++++++
2 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/gisi/modem.c b/gisi/modem.c
index 7657bd1..734c4f1 100644
--- a/gisi/modem.c
+++ b/gisi/modem.c
@@ -62,6 +62,7 @@ struct _GIsiModem {
uint8_t device;
GHashTable *services;
gboolean subs_source;
+ GIsiVersion version;
int req_fd;
int ind_fd;
guint req_watch;
@@ -539,6 +540,32 @@ guint g_isi_modem_add_to_watch(GIsiModem *modem, int fd)
return watch;
}
+gboolean g_isi_modem_set_version(GIsiModem *modem, const GIsiVersion version)
+{
+ if (modem == NULL)
+ return FALSE;
+
+ modem->version = version;
+
+ return TRUE;
+}
+
+int g_isi_modem_version_major(const GIsiModem *modem)
+{
+ if (modem == NULL)
+ return -1;
+
+ return modem->version.major;
+}
+
+int g_isi_modem_version_minor(const GIsiModem *modem)
+{
+ if (modem == NULL)
+ return -1;
+
+ return modem->version.minor;
+}
+
void *g_isi_modem_set_userdata(GIsiModem *modem, void *data)
{
void *old;
diff --git a/gisi/modem.h b/gisi/modem.h
index 83ba92c..24ca805 100644
--- a/gisi/modem.h
+++ b/gisi/modem.h
@@ -58,6 +58,12 @@ int g_isi_modem_set_device(GIsiModem *modem, uint8_t dev);
void g_isi_modem_set_trace(GIsiModem *modem, GIsiNotifyFunc notify);
void g_isi_modem_set_debug(GIsiModem *modem, GIsiDebugFunc debug);
+ gboolean g_isi_modem_set_version(GIsiModem *modem,
+ const GIsiVersion version);
+
+int g_isi_modem_version_major(const GIsiModem *modem);
+int g_isi_modem_version_minor(const GIsiModem *modem);
+
void *g_isi_modem_set_userdata(GIsiModem *modem, void *data);
void *g_isi_modem_get_userdata(GIsiModem *modem);
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH 03/18] isimodem: general build updates for wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
2011-02-15 12:30 ` [PATCH 01/18] gisi: pipe and pep for wgmodem2.5 Andreas Westin
2011-02-15 12:30 ` [PATCH 02/18] gisi: modem version detection Andreas Westin
@ 2011-02-15 12:30 ` Andreas Westin
2011-02-16 11:19 ` Aki Niemi
2011-02-15 12:30 ` [PATCH 04/18] gisi: fix subscription " Andreas Westin
` (14 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3751 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/debug.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/isimodem/debug.h | 8 +++++++
drivers/isimodem/mtc.h | 38 ++++++++++++++++++++++++++++++++++++
3 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index f93fa3d..c14acc2 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -166,6 +166,54 @@ const char *mtc_modem_state_name(enum mtc_modem_state value)
return "MTC_<UNKNOWN>";
}
+const char *mce_message_id_name(enum mce_message_id value)
+{
+ switch (value) {
+ _(MCE_MODEM_STATE_IND);
+ _(MCE_MODEM_STATE_QUERY_REQ);
+ _(MCE_MODEM_STATE_QUERY_RESP);
+ _(MCE_RF_STATE_REQ);
+ _(MCE_RF_STATE_RESP);
+ _(MCE_RF_STATE_IND);
+ _(MCE_RF_STATE_QUERY_REQ);
+ _(MCE_RF_STATE_QUERY_RESP);
+ _(MCE_POWER_OFF_REQ);
+ _(MCE_POWER_OFF_RESP);
+ }
+ return "MCE_<UNKNOWN>";
+}
+
+const char *mce_modem_state_name(enum mce_modem_state value)
+{
+ switch (value) {
+ _(MCE_NORMAL);
+ _(MCE_LOCAL);
+ _(MCE_SW_RESET);
+ _(MCE_POWER_OFF);
+ }
+ return "MCE_<UNKNOWN>";
+}
+
+const char *mce_status_info(enum mce_status_info value)
+{
+ switch (value) {
+ _(MCE_OK);
+ _(MCE_FAIL);
+ _(MCE_ALREADY_ACTIVE);
+ _(MCE_TRANSITION_ONGOING);
+ }
+ return "MCE_<UNKNOWN>";
+}
+
+const char *mce_rf_state_name(enum mce_rf_state value)
+{
+ switch (value) {
+ _(MCE_RF_OFF);
+ _(MCE_RF_ON);
+ }
+ return "MCE_RF<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 e149c2c..b92b48f 100644
--- a/drivers/isimodem/debug.h
+++ b/drivers/isimodem/debug.h
@@ -41,6 +41,14 @@ const char *ss_ussd_type_name(enum ss_ussd_type value);
const char *mtc_isi_cause_name(enum mtc_isi_cause value);
const char *mtc_message_id_name(enum mtc_message_id value);
const char *mtc_modem_state_name(enum mtc_modem_state value);
+const char *mce_rf_state_name(enum mce_rf_state value);
+
+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_subblock_name(uint8_t value);
+const char *uicc_status_name(uint8_t value);
const char *sms_gsm_cause_name(enum sms_gsm_cause value);
const char *sms_isi_cause_name(enum sms_isi_cause value);
diff --git a/drivers/isimodem/mtc.h b/drivers/isimodem/mtc.h
index 2db3e94..57e5040 100644
--- a/drivers/isimodem/mtc.h
+++ b/drivers/isimodem/mtc.h
@@ -27,9 +27,47 @@ extern "C" {
#endif
#define PN_MTC 0x15
+#define PN_MODEM_MCE 0xC2
#define MTC_TIMEOUT 5
#define MTC_STATE_REQ_TIMEOUT (6 + 5)
+enum mce_message_id {
+ MCE_MODEM_STATE_IND = 0x00,
+ MCE_MODEM_STATE_QUERY_REQ = 0x01,
+ MCE_MODEM_STATE_QUERY_RESP = 0x02,
+ MCE_RF_STATE_REQ = 0x03,
+ MCE_RF_STATE_RESP = 0x04,
+ MCE_RF_STATE_IND = 0x05,
+ MCE_RF_STATE_QUERY_REQ = 0x06,
+ MCE_RF_STATE_QUERY_RESP = 0x07,
+ MCE_POWER_OFF_REQ = 0x08,
+ MCE_POWER_OFF_RESP = 0x09
+};
+
+enum mce_rf_state {
+ MCE_RF_OFF = 0x00,
+ MCE_RF_ON = 0x01
+};
+
+enum mce_status_info {
+ MCE_OK = 0x00,
+ MCE_FAIL = 0x01,
+ MCE_ALREADY_ACTIVE = 0x06,
+ MCE_TRANSITION_ONGOING = 0x16
+};
+
+enum mce_modem_state {
+ MCE_NORMAL = 0x00,
+ MCE_LOCAL = 0x01,
+ MCE_SW_RESET = 0x80,
+ MCE_POWER_OFF = 0x81
+};
+
+enum mce_isi_action {
+ MCE_START = 0x03,
+ MCE_READY = 0x04
+};
+
enum mtc_isi_cause {
MTC_OK = 0x00,
MTC_FAIL = 0x01,
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH 04/18] gisi: fix subscription for wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (2 preceding siblings ...)
2011-02-15 12:30 ` [PATCH 03/18] isimodem: general build updates for wgmodem2.5 Andreas Westin
@ 2011-02-15 12:30 ` Andreas Westin
2011-02-16 11:16 ` Aki Niemi
2011-02-15 12:30 ` [PATCH 05/18] plugins: add plugin for u8500 Andreas Westin
` (13 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 676 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
gisi/modem.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/gisi/modem.c b/gisi/modem.c
index 734c4f1..143e761 100644
--- a/gisi/modem.c
+++ b/gisi/modem.c
@@ -370,13 +370,15 @@ static gboolean modem_subs_update(gpointer data)
if (legacy)
msg[3 + count] = mux->resource;
- else
+ else {
/* Resource field is 32bit and Little-endian */
msg[4 + count * 4 + 3] = mux->resource;
+ }
count++;
}
+ commgr.spn_dev = legacy ? modem->device : PN_DEV_MODEM;
len = legacy ? 3 + count : 4 + count * 4;
msg[2] = count;
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH 04/18] gisi: fix subscription for wgmodem2.5
2011-02-15 12:30 ` [PATCH 04/18] gisi: fix subscription " Andreas Westin
@ 2011-02-16 11:16 ` Aki Niemi
2011-02-16 11:33 ` Andreas WESTIN
0 siblings, 1 reply; 38+ messages in thread
From: Aki Niemi @ 2011-02-16 11:16 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1201 bytes --]
Hi Andreas,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
> if (legacy)
> msg[3 + count] = mux->resource;
> - else
> + else {
> /* Resource field is 32bit and Little-endian */
> msg[4 + count * 4 + 3] = mux->resource;
> + }
Curly brackets are either in both if and else, or in neither. I
actually prefer not to have them here, since the first line is just a
comment in the else statement. ;)
> count++;
> }
>
> + commgr.spn_dev = legacy ? modem->device : PN_DEV_MODEM;
> len = legacy ? 3 + count : 4 + count * 4;
> msg[2] = count;
This is not necessary, as a modem plugin is supposed to call
g_isi_modem_set_device() to set the modem->device to whatever it needs
to right after creating the GIsiModem instance.
In other words, the assumption is that when the GIsiModem instace is
actually used, all necessary internal data, such as flags and the
remote device have already been set.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH 04/18] gisi: fix subscription for wgmodem2.5
2011-02-16 11:16 ` Aki Niemi
@ 2011-02-16 11:33 ` Andreas WESTIN
2011-02-16 11:37 ` Aki Niemi
0 siblings, 1 reply; 38+ messages in thread
From: Andreas WESTIN @ 2011-02-16 11:33 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 789 bytes --]
Hi Aki,
On 2011-02-16 12:16, Aki Niemi wrote:
> Curly brackets are either in both if and else, or in neither. I
> actually prefer not to have them here, since the first line is just a
> comment in the else statement. ;)
Yes you're right :)
> This is not necessary, as a modem plugin is supposed to call
> g_isi_modem_set_device() to set the modem->device to whatever it needs
> to right after creating the GIsiModem instance.
>
> In other words, the assumption is that when the GIsiModem instace is
> actually used, all necessary internal data, such as flags and the
> remote device have already been set.
Tested and works fine, will submit a new patch for the u8500 plugin.
This is not done in the n900 plugin though, perhaps not necessary ?
Regards
Andreas
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 05/18] plugins: add plugin for u8500
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (3 preceding siblings ...)
2011-02-15 12:30 ` [PATCH 04/18] gisi: fix subscription " Andreas Westin
@ 2011-02-15 12:30 ` Andreas Westin
2011-02-16 14:26 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 06/18] plugins: add u8500 to udev Andreas Westin
` (12 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 13981 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
Makefile.am | 3 +
plugins/u8500.c | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 509 insertions(+), 0 deletions(-)
create mode 100644 plugins/u8500.c
diff --git a/Makefile.am b/Makefile.am
index 1d7f32b..1b9afe8 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..866acce
--- /dev/null
+++ b/plugins/u8500.c
@@ -0,0 +1,506 @@
+/*
+ *
+ * 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>
+
+#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;
+};
+
+static const GIsiVersion modemversion = {
+ .major = 2,
+ .minor = 5,
+};
+
+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;
+ }
+
+ if (!g_isi_modem_set_version(isimodem, modemversion))
+ return -EINVAL;
+
+ 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;
+
+ 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, "isimodem", 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, "isimodem", 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 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 int u8500_init(void)
+{
+ return ofono_modem_driver_register(&driver);
+}
+
+static void u8500_exit(void)
+{
+ 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] 38+ messages in thread* Re: [PATCH 05/18] plugins: add plugin for u8500
2011-02-15 12:30 ` [PATCH 05/18] plugins: add plugin for u8500 Andreas Westin
@ 2011-02-16 14:26 ` Aki Niemi
2011-02-16 15:27 ` Andreas WESTIN
0 siblings, 1 reply; 38+ messages in thread
From: Aki Niemi @ 2011-02-16 14:26 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1281 bytes --]
Hi,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
> +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;
> + }
> +
> + if (!g_isi_modem_set_version(isimodem, modemversion))
> + return -EINVAL;
I'm not going to add this API in GIsiModem. If we went this route, and
used vendor quirks inside the isimodem driver, then it would make a
whole lot more sense to do it in the driver create(), not here.
But we're not going that route. Each driver detects the version of the
ISI service it is talking to when it is probed.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH 05/18] plugins: add plugin for u8500
2011-02-16 14:26 ` Aki Niemi
@ 2011-02-16 15:27 ` Andreas WESTIN
2011-02-17 9:02 ` Aki Niemi
0 siblings, 1 reply; 38+ messages in thread
From: Andreas WESTIN @ 2011-02-16 15:27 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1501 bytes --]
On 2011-02-16 15:26, Aki Niemi wrote:
> Hi,
>
> 2011/2/15 Andreas Westin<andreas.westin@stericsson.com>:
>> +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;
>> + }
>> +
>> + if (!g_isi_modem_set_version(isimodem, modemversion))
>> + return -EINVAL;
>
> I'm not going to add this API in GIsiModem. If we went this route, and
> used vendor quirks inside the isimodem driver, then it would make a
> whole lot more sense to do it in the driver create(), not here.
>
> But we're not going that route. Each driver detects the version of the
> ISI service it is talking to when it is probed.
>
Yes this should not be there, but maybe I misunderstood you regarding
the version handling. I was under the impression that we checked the
version we get from doing PN_MTC or PN_MODEM_MCE ?
Cheers
Andreas
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH 05/18] plugins: add plugin for u8500
2011-02-16 15:27 ` Andreas WESTIN
@ 2011-02-17 9:02 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-17 9:02 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 976 bytes --]
Hi Andreas,
2011/2/16 Andreas WESTIN <andreas.westin@stericsson.com>:
>>> + if (!g_isi_modem_set_version(isimodem, modemversion))
>>> + return -EINVAL;
>>
>> I'm not going to add this API in GIsiModem. If we went this route, and
>> used vendor quirks inside the isimodem driver, then it would make a
>> whole lot more sense to do it in the driver create(), not here.
>>
>> But we're not going that route. Each driver detects the version of the
>> ISI service it is talking to when it is probed.
>>
>
> Yes this should not be there, but maybe I misunderstood you regarding the
> version handling. I was under the impression that we checked the version we
> get from doing PN_MTC or PN_MODEM_MCE ?
The modem driver is a bit of a special case again. There is no generic
isimodem modem driver, but each modem plugin implements their own
version. Here, just use PN_MODEM_MCE, since that is what the U8500
uses.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 06/18] plugins: add u8500 to udev
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (4 preceding siblings ...)
2011-02-15 12:30 ` [PATCH 05/18] plugins: add plugin for u8500 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 07/18] isimodem: add wgmodem2.5 to devinfo Andreas Westin
` (11 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 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 f01b739..1090cf7 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -356,6 +356,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] 38+ messages in thread* [PATCH 07/18] isimodem: add wgmodem2.5 to devinfo
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (5 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 06/18] plugins: add u8500 to udev Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-16 14:15 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
` (10 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 8482 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/debug.c | 1 +
drivers/isimodem/devinfo.c | 161 ++++++++++++++++++++++++++++++++++++--------
drivers/isimodem/info.h | 3 +
3 files changed, 136 insertions(+), 29 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/devinfo.c b/drivers/isimodem/devinfo.c
index 3bf05f4..ebe4273 100644
--- a/drivers/isimodem/devinfo.c
+++ b/drivers/isimodem/devinfo.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
@@ -46,6 +47,8 @@
struct devinfo_data {
GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
};
static void info_resp_cb(const GIsiMessage *msg, void *data)
@@ -82,7 +85,8 @@ static void info_resp_cb(const GIsiMessage *msg, void *data)
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_SN_IMEI_PLAIN &&
+ id != INFO_SB_MODEMSW_VERSION)
continue;
if (g_isi_sb_iter_get_len(&iter) < 5)
@@ -111,17 +115,22 @@ static void isi_query_manufacturer(struct ofono_devinfo *info,
struct devinfo_data *dev = ofono_devinfo_get_data(info);
struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
+ if (cbd == NULL || dev == NULL)
+ goto error;
+
+ if (g_isi_client_resource(dev->client) == PN_MODEM_INFO) {
+ goto error;
+ } else {
+
const uint8_t msg[] = {
INFO_PRODUCT_INFO_READ_REQ,
INFO_PRODUCT_MANUFACTURER
};
size_t len = sizeof(msg);
- if (cbd == NULL || dev == NULL)
- goto error;
-
if (g_isi_client_send(dev->client, msg, len, info_resp_cb, cbd, g_free))
return;
+ }
error:
CALLBACK_WITH_FAILURE(cb, "", data);
@@ -135,17 +144,22 @@ static void isi_query_model(struct ofono_devinfo *info,
struct devinfo_data *dev = ofono_devinfo_get_data(info);
struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
+ if (cbd == NULL || dev == NULL)
+ goto error;
+
+ if (g_isi_client_resource(dev->client) == PN_MODEM_INFO) {
+ goto error;
+ } else {
+
const uint8_t msg[] = {
INFO_PRODUCT_INFO_READ_REQ,
INFO_PRODUCT_NAME
};
size_t len = sizeof(msg);
- if (cbd == NULL || dev == NULL)
- goto error;
-
if (g_isi_client_send(dev->client, msg, len, info_resp_cb, cbd, g_free))
return;
+ }
error:
CALLBACK_WITH_FAILURE(cb, "", data);
@@ -159,24 +173,51 @@ static void isi_query_revision(struct ofono_devinfo *info,
struct devinfo_data *dev = ofono_devinfo_get_data(info);
struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
- const uint8_t msg[] = {
- INFO_VERSION_READ_REQ,
- 0x00, INFO_MCUSW,
- 0x00, 0x00, 0x00, 0x00
- };
- size_t len = sizeof(msg);
+ unsigned char *msg = NULL;
+ unsigned char msg_size = 0;
+ size_t len;
if (cbd == NULL || dev == NULL)
goto error;
+ if (g_isi_client_resource(dev->client) == PN_MODEM_INFO) {
+ goto error;
+ } else {
+ msg_size = 7;
+ msg = g_try_malloc0(msg_size);
+ msg[0] = INFO_VERSION_READ_REQ;
+ msg[1] = 0x00;
+ msg[2] = INFO_MCUSW;
+ msg[3] = 0x00;
+ msg[4] = 0x00;
+ msg[5] = 0x00;
+ msg[6] = 0x00;
+ }
+
+ len = sizeof(msg);
+
if (g_isi_client_send(dev->client, msg, len, info_resp_cb, cbd, g_free))
- return;
+ goto out;
error:
CALLBACK_WITH_FAILURE(cb, "", data);
+out:
+ g_free(msg);
g_free(cbd);
}
+static gboolean send_serial_number_read_req(GIsiClient *client, void *cbd,
+ GDestroyNotify destroy)
+{
+ const uint8_t msg[] = {
+ INFO_SERIAL_NUMBER_READ_REQ,
+ INFO_SN_IMEI_PLAIN
+ };
+
+ return g_isi_client_send(client, msg, sizeof(msg),
+ info_resp_cb, cbd, g_free);
+
+}
static void isi_query_serial(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
@@ -184,33 +225,84 @@ static void isi_query_serial(struct ofono_devinfo *info,
struct devinfo_data *dev = ofono_devinfo_get_data(info);
struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
- const uint8_t msg[] = {
- INFO_SERIAL_NUMBER_READ_REQ,
- INFO_SN_IMEI_PLAIN
- };
- size_t len = sizeof(msg);
+ if (cbd == NULL || dev == NULL)
+ goto error;
- if (cbd == NULL || dev == NULL)
- goto error;
+/* FIXME Move to u8500 */
+ if (g_isi_client_resource(dev->client) == PN_MODEM_INFO) {
+ char imei[16]; /* IMEI 15 digits + 1 null*/
+ char numbers[] = "1234567890";
+ FILE *fp = fopen("/etc/imei", "r");
+ DBG("");
- if (g_isi_client_send(dev->client, msg, len, info_resp_cb, cbd, g_free))
+ 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);
+ g_free(cbd);
return;
+ } else {
+ if (send_serial_number_read_req(dev->client, cbd, g_free))
+ 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_devinfo *info = data;
+ struct devinfo_data *dev = ofono_devinfo_get_data(info);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+
+ if (dev == NULL || dev->client != NULL)
+ return;
+
+ dev->client = dev->primary;
+
+ ofono_devinfo_register(info);
+ g_isi_client_destroy(dev->secondary);
+
+}
+
+static void secondary_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_devinfo *info = data;
+ struct devinfo_data *dev = ofono_devinfo_get_data(info);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ if (dev == NULL || dev->client != NULL)
+ return;
+
+ dev->client = dev->secondary;
+
ofono_devinfo_register(info);
+ g_isi_client_destroy(dev->primary);
+
}
static int isi_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
@@ -222,19 +314,30 @@ static int isi_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
if (data == NULL)
return -ENOMEM;
- data->client = g_isi_client_create(idx, PN_PHONE_INFO);
- if (data->client == NULL) {
- g_free(data);
- return -ENOMEM;
- }
+ data->primary = g_isi_client_create(idx, PN_MODEM_INFO);
+ if (data->primary == NULL)
+ goto nomem;
+ data->secondary = g_isi_client_create(idx, PN_PHONE_INFO);
+ if (data->secondary == NULL)
+ goto nomem;
ofono_devinfo_set_data(info, data);
g_isi_client_set_timeout(data->client, INFO_TIMEOUT);
- g_isi_client_verify(data->client, reachable_cb, info, NULL);
+ g_isi_client_verify(data->primary, primary_reachable_cb, info, NULL);
+ g_isi_client_verify(data->secondary, secondary_reachable_cb, info,
+ NULL);
return 0;
+
+nomem:
+ g_isi_client_destroy(data->primary);
+ g_isi_client_destroy(data->secondary);
+
+ g_free(data);
+ return -ENOMEM;
+
}
static void isi_devinfo_remove(struct ofono_devinfo *info)
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] 38+ messages in thread* Re: [PATCH 07/18] isimodem: add wgmodem2.5 to devinfo
2011-02-15 12:31 ` [PATCH 07/18] isimodem: add wgmodem2.5 to devinfo Andreas Westin
@ 2011-02-16 14:15 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-16 14:15 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 912 bytes --]
Hi,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
> @@ -111,17 +115,22 @@ static void isi_query_manufacturer(struct ofono_devinfo *info,
> struct devinfo_data *dev = ofono_devinfo_get_data(info);
> struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
>
> + if (cbd == NULL || dev == NULL)
> + goto error;
> +
> + if (g_isi_client_resource(dev->client) == PN_MODEM_INFO) {
> + goto error;
> + } else {
> +
So do I understand this right, that PN_MODEM_INFO doesn't return any
of manufacturer, model, revision, or serial information at all?
If so, then I don't understand why any of this code is here. To
implement the serial number query, you just need to implement and
register your custom devinfo driver in the U8500 plugin that reads the
serial from under /etc.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 08/18] isimodem: UICC sim support for wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (6 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 07/18] isimodem: add wgmodem2.5 to devinfo Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-17 13:55 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
` (9 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 78639 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
Makefile.am | 4 +-
drivers/isimodem/debug.c | 84 ++
drivers/isimodem/debug.h | 1 +
drivers/isimodem/sim.c | 2381 ++++++++++++++++++++++++++++++++++++++++++++--
drivers/isimodem/uicc.h | 268 ++++++
5 files changed, 2662 insertions(+), 76 deletions(-)
create mode 100644 drivers/isimodem/uicc.h
diff --git a/Makefile.am b/Makefile.am
index 1b9afe8..7de8d8a 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/sim.c b/drivers/isimodem/sim.c
index bfecbc9..0ef02f3 100644
--- a/drivers/isimodem/sim.c
+++ b/drivers/isimodem/sim.c
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,24 +34,216 @@
#include <gisi/message.h>
#include <gisi/client.h>
+#include <gisi/iter.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/sim.h>
-#include "simutil.h"
+#include <ofono/dbus.h>
+#include "simutil.h"
#include "isimodem.h"
#include "isiutil.h"
#include "sim.h"
+#include "uicc.h"
#include "debug.h"
-#define SIM_MAX_SPN_LENGTH 16
+#define PIN_PROMPT
+#define STATUS_WORD_HANDLING
+
+#define SIM_MAX_SPN_LENGTH 16
+#define CLIENT_ID 1
+
+
+/* File info parameters */
+#define FCP_TEMPLATE 0x62
+#define FCP_FILE_SIZE 0x80
+#define FCP_FILE_DESC 0x82
+#define FCP_FILE_ID 0x83
+#define FCP_FILE_LIFECYCLE 0x8A
+#define FCP_FILE_SECURITY_ARR 0x8B
+#define FCP_FILE_SECURITY_COMPACT 0x8C
+#define FCP_FILE_SECURITY_EXPANDED 0xAB
+#define FCP_PIN_STATUS 0xC6
+#define SIM_EFARR_FILEID 0x6F06
+#define ADF_USIM 0x7FFF
+#define MAX_SIM_APPS 10
+#define NOT_AVAILABLE -1
+#define NOT_ACTIVATED -1
struct sim_data {
GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
+ gboolean iccid;
gboolean registered;
+ gboolean uicc_app_started;
+ gboolean pin_state_received;
+ gboolean passwd_required;
+ int app_id;
+ int trying_app_id;
+ int app_type;
+ int trying_app_type;
+ uint8_t client_id;
+ uint8_t current_pin_id;
+ uint8_t pin1_id;
+ uint8_t pin2_id;
+};
+
+struct ofono_sim_local {
+ char *iccid;
+ char *imsi;
+ enum ofono_sim_phase phase;
+ unsigned char mnc_length;
+ GSList *own_numbers;
+ GSList *new_numbers;
+ GSList *service_numbers;
+ gboolean sdn_ready;
+ enum ofono_sim_state state;
+ enum ofono_sim_password_type pin_type;
+ gboolean locked_pins[OFONO_SIM_PASSWORD_INVALID];
+ char **language_prefs;
+ GQueue *simop_q;
+ gint simop_source;
+ unsigned char efmsisdn_length;
+ unsigned char efmsisdn_records;
+ unsigned char *efli;
+ unsigned char efli_length;
+ enum ofono_sim_cphs_phase cphs_phase;
+ unsigned char cphs_service_table[2];
+ struct ofono_watchlist *state_watches;
+ const struct ofono_sim_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
+ DBusMessage *pending;
+};
+
+struct sim_passwd_to_pin_id {
+ uint8_t passwd_type;
+ uint8_t pin_id;
+};
+
+static struct sim_passwd_to_pin_id const pin_ids[] = {
+ {OFONO_SIM_PASSWORD_NONE, 0},
+ {OFONO_SIM_PASSWORD_SIM_PIN, 1},
+ {OFONO_SIM_PASSWORD_PHSIM_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHFSIM_PIN, 0},
+ {OFONO_SIM_PASSWORD_SIM_PIN2, -1},
+ {OFONO_SIM_PASSWORD_PHNET_PIN, 0x11},
+ {OFONO_SIM_PASSWORD_PHNETSUB_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHSP_PIN, 0},
+ {OFONO_SIM_PASSWORD_PHCORP_PIN, 0},
+ {OFONO_SIM_PASSWORD_SIM_PUK, -1},
+ {OFONO_SIM_PASSWORD_PHFSIM_PUK, 0},
+ {OFONO_SIM_PASSWORD_SIM_PUK2, -1},
+ {OFONO_SIM_PASSWORD_PHNET_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHNETSUB_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHSP_PUK, 0},
+ {OFONO_SIM_PASSWORD_PHCORP_PUK, 0},
+ {OFONO_SIM_PASSWORD_INVALID, 0}
+};
+
+const uint8_t upin_id = 0x11;
+
+/* Current SIM */
+static struct ofono_sim *uicc_sim;
+/* UICC client */
+static GIsiClient *pn_uicc_client;
+static int uicc_users;
+
+struct sim_applications {
+ int app_list[MAX_SIM_APPS];
+ int app_type[MAX_SIM_APPS];
+};
+
+struct sim_applications *sim_application_list_p;
+
+struct file_info {
+ int fileid;
+ int length;
+ int structure;
+ int record_length;
+ uint8_t access[3];
+ uint8_t file_status;
+};
+
+static struct file_info const static_file_info[] = {
+ {
+ SIM_EFSPN_FILEID, 17, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 0, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EF_ICCID_FILEID, 10, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 10, { 0x0f, 0xff, 0xee }
+ },
+ {
+ SIM_EFPL_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0f, 0xff, 0xff }
+ }, /* not found */
+ {
+ SIM_EFLI_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0f, 0xff, 0xff }
+ }, /* not found */
+ {
+ SIM_EFMSISDN_FILEID, 28, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 28, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFAD_FILEID, 20, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 20, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFPHASE_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 1, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFPNN_FILEID, 4 * 18, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 18, { 0x0e, 0xff, 0xee }
+ }, /* 4 records, name 16 bytes */
+ {
+ SIM_EFOPL_FILEID, 4 * 24, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 24, { 0x0e, 0xff, 0xee }
+ }, /* 4 records, name 16 bytes */
+ {
+ SIM_EFMBI_FILEID, 5, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 5, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFMWIS_FILEID, 6, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 6, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFSPDI_FILEID, 64, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 64, { 0x0e, 0xff, 0xee }
+ },
+ {
+ SIM_EFECC_FILEID, 5 * 3, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 3, { 0x0e, 0xff, 0xee }
+ }, /* Can be also FIXED in 3G */
+ {
+ SIM_EFCBMIR_FILEID, 8 * 4, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 4, { 0x01, 0xff, 0xee }
+ }, /* 8 records */
+ {
+ SIM_EFCBMI_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 2, { 0x01, 0xff, 0xee }
+ }, /* 8 records */
+ {
+ SIM_EFCBMID_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 2, { 0x01, 0xff, 0x11 }
+ }, /* 8 records */
+ {
+ SIM_EFSMSP_FILEID, 56, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ 56, { 0x01, 0xff, 0xee }
+ },
+ {
+ SIM_EFIMSI_FILEID, 9, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 9, { 0x0e, 0xff, 0xee }
+ },
};
+static uint8_t get_sfi(const int fileid);
+
struct sim_imsi {
uint8_t length;
uint8_t imsi[8];
@@ -66,14 +259,283 @@ struct sim_spn {
uint8_t disp_roam;
};
-struct file_info {
- int fileid;
- int length;
- int structure;
- int record_length;
- uint8_t access[3];
- uint8_t file_status;
-};
+static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
+ struct sim_data *sd,
+ uint16_t *length,
+ uint16_t *record_length,
+ uint8_t *records,
+ uint8_t *structure);
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ ofono_sim_passwd_cb_t cb,
+ void *data,
+ uint8_t service);
+
+static void uicc_application_activate_req(GIsiClient *client,
+ void *opaque,
+ unsigned char appl_type,
+ unsigned char aid);
+
+static int sim_applications_get_next_index(struct sim_applications *sa,
+ int current_app)
+{
+ if (current_app < (MAX_SIM_APPS - 1)) {
+ int i;
+
+ for (i = ++current_app; i < MAX_SIM_APPS; i++) {
+ if (sa->app_list[i] &&
+ (sa->app_type[i] != UICC_APPL_TYPE_UNKNOWN))
+ 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;
+}
+
+static uint8_t get_sfi(const int fileid)
+{
+ uint8_t ret;
+
+ /* SFI list from 3GPP TS 31.102 Annex H */
+ switch (fileid) {
+ case SIM_EFECC_FILEID:
+ ret = 01;
+ break;
+ case SIM_EFLI_FILEID:
+ ret = 02;
+ break;
+ case SIM_EFAD_FILEID:
+ ret = 03;
+ break;
+ case SIM_EFIMSI_FILEID:
+ ret = 07;
+ break;
+ case SIM_EFCBMID_FILEID:
+ ret = 0x0E;
+ break;
+ case SIM_EFPNN_FILEID:
+ ret = 0x19;
+ break;
+ case SIM_EFOPL_FILEID:
+ ret = 0x1A;
+ break;
+ default:
+ ret = UICC_SFI_NOT_PRESENT;
+ break;
+ }
+
+ return ret;
+}
+
+int get_app_id(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("app_id %d", sd->app_id);
+ return sd->app_id;
+ } else
+ return -1;
+}
+
+int get_app_type(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("app_type %d", sd->app_type);
+ return sd->app_type;
+ } else
+ return -1;
+}
+
+int get_client_id(void)
+{
+ if (uicc_sim) {
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ DBG("client_id %d", sd->client_id);
+ return sd->client_id;
+ } else
+ return -1;
+}
+
+GIsiClient *read_pn_uicc_client(void)
+{
+ return pn_uicc_client;
+}
+
+struct ofono_sim *get_sim(void)
+{
+ return uicc_sim;
+}
/* Returns file info */
static gboolean fake_file_info(gpointer user)
@@ -89,29 +551,6 @@ static gboolean fake_file_info(gpointer user)
return FALSE;
}
-static void isi_read_file_info(struct ofono_sim *sim, int fileid,
- ofono_sim_file_info_cb_t cb, void *data)
-{
- int i;
- static struct file_info const info[] = {
- { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
- { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
- };
- int N = sizeof(info) / sizeof(info[0]);
- struct isi_cb_data *cbd;
-
- for (i = 0; i < N; i++) {
- if (fileid == info[i].fileid) {
- cbd = isi_cb_data_new((void *) &info[i], cb, data);
- g_idle_add(fake_file_info, cbd);
- return;
- }
- }
-
- DBG("Fileid %04X not implemented", fileid);
- CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
-}
-
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
uint8_t service)
{
@@ -129,7 +568,10 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
return FALSE;
}
- if (!g_isi_msg_data_get_byte(msg, 1, &cause) || cause != SIM_SERV_OK) {
+ if ((!g_isi_msg_data_get_byte(msg, 1, &cause) ||
+ cause != SIM_SERV_OK) &&
+ (!g_isi_msg_data_get_byte(msg, 2, &cause) ||
+ cause != UICC_STATUS_OK)) {
DBG("Request failed: %s", sim_isi_cause_name(cause));
return FALSE;
}
@@ -141,6 +583,303 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
return TRUE;
}
+static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
+ struct sim_data *sd,
+ uint16_t *length,
+ uint16_t *record_length,
+ uint8_t *records, uint8_t *structure)
+{
+ uint8_t fcp;
+ uint8_t fcp_len;
+ uint8_t read = 0;
+ uint8_t id;
+ uint8_t item_len;
+ uint16_t file_id;
+ uint8_t desc;
+ uint8_t coding;
+ uint8_t pin_do_len;
+ uint8_t pin_len;
+ uint8_t pin_tag;
+ uint8_t pin_id;
+ uint8_t pin_tag_pos;
+
+
+ (void)g_isi_sb_iter_get_byte(iter, &fcp, 8);
+ if (fcp == FCP_TEMPLATE) {
+ (void) g_isi_sb_iter_get_byte(iter, &fcp_len, 9);
+ while (read < fcp_len) {
+ (void) g_isi_sb_iter_get_byte(iter, &id, read + 10);
+ (void) g_isi_sb_iter_get_byte(iter, &item_len,
+ read + 11);
+
+ switch (id) {
+ case FCP_FILE_SIZE:
+ if (item_len == 2) {
+ g_isi_sb_iter_get_word(iter, length,
+ read + 10 + 2);
+ }
+ break;
+ case FCP_FILE_ID:
+
+ if (item_len == 2) {
+ g_isi_sb_iter_get_word(iter, &file_id,
+ read + 10 + 2);
+ }
+ break;
+ case FCP_FILE_DESC:
+ if (item_len >= 2) {
+ g_isi_sb_iter_get_byte(iter, &desc,
+ read + 10 + 2);
+ g_isi_sb_iter_get_byte(iter, &coding,
+ read + 10 + 3);
+ }
+
+ if (item_len >= 4) {
+ g_isi_sb_iter_get_word(iter,
+ record_length,
+ read + 10 + 4);
+ g_isi_sb_iter_get_byte(iter, records,
+ read + 10 + 6);
+ }
+ break;
+ case FCP_PIN_STATUS:
+ g_isi_sb_iter_get_byte(iter, &pin_do_len,
+ read + 10 + 3);
+ pin_tag_pos = read + 10 + 4 + pin_do_len;
+ g_isi_sb_iter_get_byte(iter, &pin_tag,
+ pin_tag_pos);
+
+ while (pin_tag == 0x83) {
+
+ g_isi_sb_iter_get_byte(iter, &pin_len,
+ pin_tag_pos + 1);
+ g_isi_sb_iter_get_byte(iter, &pin_id,
+ pin_tag_pos + 2);
+
+ pin_tag_pos += 2 + pin_len;
+ g_isi_sb_iter_get_byte(iter, &pin_tag,
+ pin_tag_pos);
+
+ if ((0x01 <= pin_id) &&
+ (pin_id <= 0x08))
+ sd->pin1_id = pin_id;
+ else if ((0x81 <= pin_id) &&
+ (pin_id <= 0x88))
+ sd->pin2_id = pin_id;
+ read += item_len + 2;
+ }
+ break;
+ case FCP_FILE_SECURITY_ARR:
+ case FCP_FILE_SECURITY_COMPACT:
+ case FCP_FILE_SECURITY_EXPANDED:
+
+ /* Not implemented, using
+ * static access rules as these
+ * are used only for caching
+ * See ETSI TS 102 221, ch
+ * 11.1.1.4.7 and
+ * Annexes E,F and G
+ */
+ case FCP_FILE_LIFECYCLE:
+ default:
+ DBG("FCP id %02X not supported", id);
+ break;
+ }
+
+ /*Data length + id size + len size */
+ read += item_len + 2;
+ }
+ }
+ if ((desc & 7) == 1)
+ *structure = OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
+ else if ((desc & 7) == 2)
+ *structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
+ else if ((desc & 7) == 6)
+ *structure = OFONO_SIM_FILE_STRUCTURE_CYCLIC;
+}
+
+static void isi_file_info_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_file_info_cb_t cb = cbd->cb;
+ uint16_t length = 0;
+ uint16_t record_length = 0;
+ uint8_t structure = -1;
+ uint8_t records = 0;
+ uint16_t file_id = 0;
+ uint8_t access[3] = {0, 0, 0};
+ uint8_t item_len = 0;
+ gboolean everything_ok = FALSE;
+ /*Access is read from static file info*/
+ struct file_info const *info = cbd->user;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_FILE_INFO))
+ goto error;
+
+ if (info != NULL) {
+ access[0] = info->access[0];
+ access[1] = info->access[1];
+ access[2] = info->access[2];
+ }
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FCI:
+ DBG("UICC_SB_FCI");
+ everything_ok = TRUE;
+
+ switch (sd->app_type) {
+ case UICC_APPL_TYPE_UICC_USIM:
+ DBG("UICC_APPL_TYPE_UICC_USIM");
+ handle_app_uicc_usim(&iter, sd,
+ &length, &record_length,
+ &records, &structure);
+
+ break;
+ case UICC_APPL_TYPE_ICC_SIM:
+ DBG("UICC_APPL_TYPE_ICC_SIM");
+ g_isi_sb_iter_get_word(&iter, &length, 10);
+ g_isi_sb_iter_get_word(&iter, &file_id, 12);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 16);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 17);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &access[0],
+ 18);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &item_len, 20);
+ (void)g_isi_sb_iter_get_byte(&iter,
+ &structure,
+ 21);
+
+ if (item_len == 2)
+ (void)g_isi_sb_iter_get_byte(&iter,
+ (uint8_t *)&record_length,
+ 22);
+
+ break;
+ default:
+ DBG("UICC application type %d not supported",
+ sd->app_type);
+ break;
+ }
+
+ break;
+ default:
+ DBG("Skipping SB");
+ break;
+ }
+
+ if (g_isi_sb_iter_next(&iter) == FALSE)
+ goto error;
+ }
+
+ if (everything_ok) {
+ CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
+ access, '\n', cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading file info");
+ CALLBACK_WITH_FAILURE(cb, 0, 0, 0, access, '\n', cbd->data);
+}
+
+static void isi_read_file_info(struct ofono_sim *sim, int fileid,
+ ofono_sim_file_info_cb_t cb, void *data)
+{
+ int i;
+ static struct file_info const info[] = {
+ { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
+ { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
+ };
+ int N = sizeof(info) / sizeof(info[0]);
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd;
+
+ if ((sd != NULL) && g_isi_client_resource(sd->client) == PN_UICC) {
+ /* Prepare for static file info used for access rights */
+ int i;
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+
+ N = sizeof(static_file_info) / sizeof(static_file_info[0]);
+ cbd = isi_cb_data_new(NULL, cb, data);
+ DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
+
+ for (i = 0; i < N; i++) {
+ if (fileid == static_file_info[i].fileid &&
+ cbd != NULL) {
+ cbd->user = (void *) &static_file_info[i];
+ continue;
+ }
+ }
+ if (!get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ g_free(cbd);
+ goto error;
+ }
+ if (cbd) {
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_FILE_INFO,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1*/
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid), /* Elementary file short id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF,
+ };
+ g_isi_client_send(sd->client, msg, sizeof(msg),
+ isi_file_info_resp, cbd, g_free);
+ return;
+ }
+ } else {
+ for (i = 0; i < N; i++) {
+ if (fileid == info[i].fileid) {
+ cbd = isi_cb_data_new((void *) &info[i], cb,
+ data);
+ g_idle_add(fake_file_info, cbd);
+ return;
+ }
+ }
+
+ }
+error:
+ DBG("Fileid %04X not implemented", fileid);
+ CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
+}
+
static void spn_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
@@ -234,32 +973,142 @@ static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
read_iccid_resp_cb, cbd, g_free);
}
+static void isi_read_file_transparent_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
+ uint32_t filelen = 0;
+ unsigned char filedata[256] = { 0xff };
+ gboolean everything_ok = FALSE;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_READ_TRANSPARENT))
+ goto error;
+
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FILE_DATA:
+ g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+ memmove(&filedata, iter.start + 8, filelen);
+ everything_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ if (everything_ok) {
+ DBG("Transparent EF read: 1st byte %02x, len %d",
+ filedata[0], filelen);
+ CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading transparent EF");
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
static void isi_read_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length,
ofono_sim_read_cb_t cb, void *data)
{
+ struct sim_data *sd = ofono_sim_get_data(sim);
struct isi_cb_data *cbd;
gboolean done;
cbd = isi_cb_data_new(sim, cb, data);
- if (cbd == NULL)
+
+ if (cbd == NULL || sd == NULL)
goto error;
- switch (fileid) {
- case SIM_EFSPN_FILEID:
- done = isi_read_spn(sim, cbd);
- break;
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+
+ DBG("File ID=%04X, client %d, AID %d",
+ fileid, sd->client_id, sd->app_id);
+
+ if (get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_READ_TRANSPARENT,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 3, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xff,
+ 0,
+ 8, /*Sub block length*/
+ 0, 0, 0, /* Filler */
+ sd->client_id,
+ /* Subblock 2*/
+ UICC_SB_TRANSPARENT >> 8,
+ UICC_SB_TRANSPARENT & 0xff,
+ 0, /*Sub block length*/
+ 8, /*Sub block length*/
+ 0, /*File offset (0=beginning)*/
+ 0, /*File offset (0=beginning)*/
+ 0, /*Data amount (0=all)*/
+ 0, /*Data amount (0=all)*/
+ /* Subblock 3 */
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /* Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid),/*Elementary file short id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF
+ };
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ isi_read_file_transparent_resp, cbd, g_free);
+ return;
+ }
+ goto error;
- case SIM_EF_ICCID_FILEID:
- done = isi_read_iccid(sim, cbd);
- break;
+ } else {
+ switch (fileid) {
+ case SIM_EFSPN_FILEID:
+ done = isi_read_spn(sim, cbd);
+ break;
- default:
- done = FALSE;
- }
+ case SIM_EF_ICCID_FILEID:
+ done = isi_read_iccid(sim, cbd);
+ break;
- if (done)
- return;
+ default:
+ done = FALSE;
+ }
+
+ if (done)
+ return;
+ }
DBG("Fileid %04X not implemented", fileid);
@@ -268,12 +1117,125 @@ error:
g_free(cbd);
}
-static void isi_read_file_linear(struct ofono_sim *sim, int fileid,
- int record, int length,
- ofono_sim_read_cb_t cb, void *data)
+static void isi_read_file_linear_fixed_resp(const GIsiMessage *msg, void *data)
{
- DBG("Fileid %04X not implemented", fileid);
+ struct isi_cb_data *cbd = data;
+ ofono_sim_read_cb_t cb = cbd->cb;
+ uint32_t filelen = 0;
+ unsigned char filedata[256] = { 0xff };
+ gboolean everything_ok = FALSE;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_READ_LINEAR_FIXED))
+ goto error;
+
+ everything_ok = FALSE;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_FILE_DATA:
+ g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+ memmove(&filedata, iter.start + 8, filelen);
+ everything_ok = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ if (everything_ok) {
+ DBG("Linear fixed EF read: 1st byte %02x, len %d",
+ filedata[0], filelen);
+ CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+ return;
+ }
+
+error:
+ DBG("Error reading linear fixed EF");
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
+static void isi_read_file_linear(struct ofono_sim *sim,
+ int fileid,
+ int record,
+ int rec_length,
+ ofono_sim_read_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+ DBG("File ID=%04X, record %d, client %d AID %d",
+ fileid, record, sd->client_id, sd->app_id);
+ if (!get_fileid_path(sim, &mf_path,
+ &df1_path, &df2_path, &df_len, fileid))
+ goto error;
+ if ((cbd != NULL) && (sd != NULL)) {
+
+ const unsigned char msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_READ_LINEAR_FIXED,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED, /*Session ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 3, /*number of subblocks*/
+ /* Subblock 1*/
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xff,
+ 0,
+ 8, /*Sub block length */
+ 0, 0, 0, /* Filler */
+ sd->client_id,
+ /* Subblock 2 */
+ UICC_SB_LINEAR_FIXED >> 8,
+ UICC_SB_LINEAR_FIXED & 0xff,
+ 0, /*Sub block length*/
+ 8, /*Sub block length*/
+ record, /*Record*/
+ 0, /*Record offset (0=beginning)*/
+ rec_length & 0xff, /*Data amount (0=all)*/
+ 0, /*Filler*/
+ /* Subblock 3*/
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ fileid >> 8, /* UICC elementary file ID*/
+ fileid & 0xFF,
+ get_sfi(fileid), /* Elementary file short file id*/
+ 0, /*filler*/
+ df_len, /*DF Path length*/
+ 0, /*Filler*/
+ mf_path >> 8,
+ mf_path & 0xff,
+ df1_path >> 8, /*DF Path*/
+ df1_path & 0xFF,
+ df2_path >> 8, /*DF Path*/
+ df2_path & 0xFF
+ };
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ isi_read_file_linear_fixed_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("Not implemented (fileid = %04x)", fileid);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+ g_free(cbd);
}
static void isi_read_file_cyclic(struct ofono_sim *sim, int fileid,
@@ -293,13 +1255,123 @@ static void isi_write_file_transparent(struct ofono_sim *sim, int fileid,
CALLBACK_WITH_FAILURE(cb, data);
}
+static void write_file_linear_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_write_cb_t cb = cbd->cb;
+ DBG("");
+
+ if (check_response_status(msg, UICC_APPL_CMD_RESP,
+ UICC_APPL_UPDATE_LINEAR_FIXED))
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+}
+
static void isi_write_file_linear(struct ofono_sim *sim, int fileid,
int record, int length,
const unsigned char *value,
ofono_sim_write_cb_t cb, void *data)
{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ int mf_path = 0;
+ int df1_path = 0;
+ int df2_path = 0;
+ unsigned char df_len = 0;
+ size_t i = 0;
+ size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
+ size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
+ uint8_t *fill_data = g_try_malloc0(fill_count);
+
+ DBG("");
+
+ if (!fill_data && fill_count > 0) {
+ g_free(fill_data);
+ goto error;
+ }
+ for (i = 0; i < fill_count; i++)
+ fill_data[i] = 0x00;
+
+ if (!sd->app_id || !sd->client_id || !sd || !sd->client ||
+ !cbd) {
+ DBG("Parameter error");
+ g_free(fill_data);
+ goto error;
+ }
+
+ if (get_fileid_path(sim, &mf_path, &df1_path,
+ &df2_path, &df_len, fileid)) {
+ uint8_t msg[] = {
+ UICC_APPL_CMD_REQ,
+ UICC_APPL_UPDATE_LINEAR_FIXED,
+ sd->app_id,
+ UICC_SESSION_ID_NOT_USED,
+ 0x00, 0x00, /* fillers */
+ 0x04, /* nro of sub blocks */
+ /* 1st subblock */
+ UICC_SB_CLIENT >> 8,
+ UICC_SB_CLIENT & 0xFF,
+ 0x00, 0x08, /* subblock length */
+ 0x00, 0x00, 0x00, /* fillers */
+ sd->client_id,
+ /* 2nd subblock */
+ UICC_SB_LINEAR_FIXED >> 8,
+ UICC_SB_LINEAR_FIXED & 0xFF,
+ 0x00, 0x08, /* subblock length */
+ record, /* the record in the file*/
+ 0x00, /* record offset (0 == beginning) */
+ 0x00, /* data amount, used only for reading */
+ 0x00, /* filler */
+ /* 3th subblock */
+ UICC_SB_APPL_PATH >> 8,
+ UICC_SB_APPL_PATH & 0xFF,
+ 0x00, 0x10, /* subblock length */
+ fileid >> 8, /* elementary file id */
+ fileid & 0xFF,
+ get_sfi(fileid),
+ 0x00, /* filler */
+ df_len, /* path length */
+ 0x00, /* filler */
+ mf_path >> 8, /* DF Path MF */
+ mf_path & 0xFF,
+ df1_path >> 8, /* DF Path */
+ df1_path & 0xFF,
+ df2_path >> 8, /* DF Path */
+ df2_path & 0xFF,
+ /* 4nd subblock */
+ UICC_SB_FILE_DATA >> 8,
+ UICC_SB_FILE_DATA & 0xFF,
+ sb_file_data_legth >> 8, /* subblock length */
+ sb_file_data_legth & 0xFF,
+ length >> 24, /* data length */
+ length >> 16, /* need to be shifted */
+ length >> 8,
+ length & 0xFF,
+ };
+
+ struct iovec iov[3] = {
+ { msg, sizeof(msg) },
+ { (uint8_t *)value, length },
+ { fill_data, fill_count },
+ };
+
+ if (!g_isi_client_vsend_with_timeout(sd->client, iov,
+ 3, SIM_TIMEOUT, write_file_linear_cb,
+ cbd, g_free)) {
+ g_free(fill_data);
+ goto error;
+ }
+
+ g_free(fill_data);
+ return;
+ }
+ }
DBG("Fileid %04X not implemented", fileid);
+error:
CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
}
static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
@@ -309,10 +1381,53 @@ static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
DBG("Fileid %04X not implemented", fileid);
CALLBACK_WITH_FAILURE(cb, data);
}
-
-static void imsi_resp_cb(const GIsiMessage *msg, void *data)
+static void uicc_read_imsi_resp(const struct ofono_error *error,
+ const unsigned char *data,
+ int len,
+ void *user)
{
- struct isi_cb_data *cbd = data;
+ struct isi_cb_data *cbd = user;
+ ofono_sim_imsi_cb_t cb = cbd->cb;
+ /* For coding see TS 24.008 */
+ char imsi[SIM_MAX_IMSI_LENGTH + 1];
+ int i = 1; /*Skip length, the 1st byte*/
+ int j = 0;
+ int octets;
+
+ if (data == NULL)
+ goto error;
+
+ octets = data[0];
+
+ if (octets != 8 || octets > len)
+ goto error;
+
+ /* Ignore the low-order semi-octet of the first byte */
+ imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
+
+ for (i++, j++; i - 1 < octets && j < SIM_MAX_IMSI_LENGTH; i++) {
+ char nibble;
+ imsi[j++] = (data[i] & 0x0F) + '0';
+ nibble = (data[i] & 0xF0) >> 4;
+
+ if (nibble != 0x0F)
+ imsi[j++] = nibble + '0';
+ }
+
+ imsi[j] = '\0';
+ DBG("IMSI %s", imsi);
+ CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
+ goto out;
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+out:
+ g_free(cbd);
+ return;
+}
+
+static void imsi_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
ofono_sim_imsi_cb_t cb = cbd->cb;
struct sim_imsi *resp;
@@ -321,9 +1436,6 @@ static void imsi_resp_cb(const GIsiMessage *msg, void *data)
char imsi[SIM_MAX_IMSI_LENGTH + 1];
size_t i, j;
- if (!check_response_status(msg, SIM_IMSI_RESP_READ_IMSI, READ_IMSI))
- goto error;
-
if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
goto error;
@@ -352,16 +1464,24 @@ static void isi_read_imsi(struct ofono_sim *sim,
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ size_t len;
const uint8_t msg[] = {
SIM_IMSI_REQ_READ_IMSI,
READ_IMSI
};
- size_t len = sizeof(msg);
if (cbd == NULL || sd == NULL)
goto error;
+ if (g_isi_client_resource(sd->client) == PN_UICC) {
+ isi_read_file_transparent(sim, SIM_EFIMSI_FILEID, 0, 9,
+ uicc_read_imsi_resp, cbd);
+ return;
+ }
+ len = sizeof(msg);
+
+
if (g_isi_client_send(sd->client, msg, len, imsi_resp_cb, cbd, g_free))
return;
@@ -370,6 +1490,976 @@ error:
g_free(cbd);
}
+static void uicc_application_activate_resp(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ uint8_t *msg_data = (uint8_t *)g_isi_msg_data(msg);
+
+ if (!check_response_status(msg, UICC_APPLICATION_RESP,
+ UICC_APPL_HOST_ACTIVATE))
+ return;
+
+ if ((msg_data[2] == UICC_STATUS_OK) ||
+ (msg_data[2] == UICC_STATUS_APPL_ACTIVE)) {
+ if (!sd->uicc_app_started) {
+ sd->app_id = sd->trying_app_id;
+ sd->app_type = sd->trying_app_type;
+ sd->uicc_app_started = TRUE;
+ DBG("UICC application activated");
+ ofono_sim_inserted_notify(sim, TRUE);
+ ofono_sim_register(sim);
+ g_free(sim_application_list_p);
+ }
+ } else {
+ int i = sim_applications_get_next_index(
+ sim_application_list_p, sd->trying_app_id);
+
+ if (i == NOT_AVAILABLE) {
+ g_free(sim_application_list_p);
+ return;
+ }
+
+ DBG("Activation Error, trying to activate APP with ID:%d", i);
+ uicc_application_activate_req(sd->client, sim,
+ sim_application_list_p->app_type[i],
+ sim_application_list_p->app_list[i]);
+ return;
+ }
+
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_CLIENT: {
+ guint8 client = 0;
+ g_isi_sb_iter_get_byte(&iter, &client, 7);
+ DBG("Client id %d", client);
+ sd->client_id = client;
+ break;
+ }
+ case UICC_SB_FCI:
+ DBG("UICC_SB_FCI");
+
+ if (sd->app_type == UICC_APPL_TYPE_UICC_USIM) {
+ uint16_t length, record_length;
+ uint8_t records, structure;
+ handle_app_uicc_usim(&iter, sd, &length,
+ &record_length, &records,
+ &structure);
+ }
+
+ break;
+ case UICC_SB_CHV:
+ DBG("UICC_SB_CHV");
+
+ if (sd->app_type == UICC_APPL_TYPE_ICC_SIM) {
+ uint8_t chv_id = 0, pin_id = 0;
+ (void) g_isi_sb_iter_get_byte(&iter,
+ &chv_id, 4);
+ (void) g_isi_sb_iter_get_byte(&iter,
+ &pin_id, 5);
+ DBG("UICC_APPL_TYPE_UICC_SIM");
+
+ if (chv_id == 1)
+ sd->pin1_id = pin_id;
+ else if (chv_id == 2)
+ sd->pin2_id = pin_id;
+ }
+
+ break;
+ default:
+ DBG("Skipping sub-block: %s (%zu bytes)",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+
+ (void)g_isi_sb_iter_next(&iter);
+ }
+}
+
+static void uicc_application_activate_req(GIsiClient *client,
+ void *opaque,
+ unsigned char appl_type,
+ unsigned char aid)
+{
+ const unsigned char msg[] = {
+ UICC_APPLICATION_REQ,
+ UICC_APPL_HOST_ACTIVATE,
+ 2, /* number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_APPLICATION >> 8,
+ UICC_SB_APPLICATION & 0xff,
+ 0, /*subblock length*/
+ 8, /*subblock length*/
+ 0, /*filler*/
+ 0, /*filler*/
+ appl_type,
+ aid,
+ /* Subblock 2 */
+ UICC_SB_APPL_INFO >> 8,
+ UICC_SB_APPL_INFO & 0xff,
+ 0, /*subblock length*/
+ 8, /*subblock length*/
+ 0, /*filler*/
+ 0, /*filler*/
+ 0, /*filler*/
+ /* whether the application initialization procedure
+ * will follow the activation or not */
+ UICC_APPL_START_UP_INIT_PROC
+ };
+
+ DBG("Appl type %d, AID %d", appl_type, aid);
+
+ g_isi_client_send_with_timeout(
+ client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_application_activate_resp, opaque, NULL);
+}
+
+static void uicc_application_list_resp(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sim *sim = data;
+ gboolean everything_ok = TRUE;
+ int index = NOT_AVAILABLE;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ if (!check_response_status(msg, UICC_APPLICATION_RESP,
+ UICC_APPL_LIST)) {
+ uint8_t status = 0;
+
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ if (status != UICC_STATUS_FAIL)
+ return;
+ everything_ok = FALSE;
+ }
+
+ sim_application_list_p = g_try_new0(struct sim_applications, 1);
+
+ if (everything_ok) {
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(
+ g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_APPL_DATA_OBJECT: {
+ guint8 appl_id = -1;
+ guint8 appl_type = -1;
+ guint8 status = -1;
+ gboolean ret;
+ ret = g_isi_sb_iter_get_byte(
+ &iter, &appl_type, 6);
+ ret = g_isi_sb_iter_get_byte(
+ &iter, &appl_id, 7);
+ (void) g_isi_sb_iter_get_byte(
+ &iter, &status, 8);
+ DBG("Appl type=%d, Appl id=%d, Appl status=%d",
+ appl_type, appl_id, status);
+
+ sim_application_list_p->app_list[appl_id] =
+ appl_id;
+ sim_application_list_p->app_type[appl_id] =
+ appl_type;
+ break;
+ }
+ default:
+ DBG("Skipping sub-block: %s (%zu bytes)",
+ uicc_subblock_name(
+ g_isi_sb_iter_get_id(&iter)),
+ g_isi_sb_iter_get_len(&iter));
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+ }
+
+ if (!sd->uicc_app_started) {
+ index = sim_applications_get_next_index(sim_application_list_p,
+ NOT_ACTIVATED);
+
+ if (index != NOT_AVAILABLE) {
+ DBG("Activating APP index:%d", index);
+ sd->trying_app_id =
+ sim_application_list_p->app_list[index];
+ sd->trying_app_type =
+ sim_application_list_p->app_type[index];
+ DBG("Activating APP ID: %d APP type: %d",
+ sd->trying_app_id, sd->trying_app_type);
+ uicc_application_activate_req(sd->client, sim,
+ sim_application_list_p->app_type[index],
+ sim_application_list_p->app_list[index]);
+ } else
+ g_free(sim_application_list_p);
+ }
+}
+
+static void uicc_application_list_req(GIsiClient *client,
+ void *opaque)
+{
+ const unsigned char msg[] = {
+ UICC_APPLICATION_REQ,
+ UICC_APPL_LIST,
+ 0 /* number of subblocks*/
+ };
+ DBG("");
+
+ g_isi_client_send_with_timeout(
+ client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_application_list_resp, opaque, NULL);
+}
+
+static void uicc_pin_enter_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct ofono_error error;
+ GIsiSubBlockIter iter;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+ uint8_t status = 0, sbcount = 0;
+
+ if (msg == NULL)
+ goto error;
+
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ if (status == UICC_STATUS_OK) {
+ sd->passwd_required = FALSE;
+ error.type = OFONO_ERROR_TYPE_NO_ERROR;
+ error.error = 0;
+ goto out;
+ }
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ error.type = OFONO_ERROR_TYPE_FAILURE;
+ error.error = 1;
+out:
+ cb(&error, cbd->data);
+}
+
+static void uicc_pin_enter(struct ofono_sim *sim, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
+ DBG("PIN=%s PINID=%02x", passwd, sd->current_pin_id);
+
+ if (cbd && sd) {
+ unsigned char pinlen = strlen(passwd);
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ UICC_PIN_VERIFY,
+ sd->app_id,
+ 0, /* Filler */
+ 0, /* Filler */
+ 0, /* Filler */
+ 1, /* number of subblocks */
+ /* Subblock 1 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /* Max length */
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_OLD, /* PIN qualifier */
+ pinlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+
+ memmove(&msg[14], passwd, pinlen);
+
+ g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SIM_TIMEOUT, uicc_pin_enter_resp, cbd,
+ g_free);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+}
+
+enum ofono_sim_password_type passwd_type_for_query =
+ OFONO_SIM_PASSWORD_SIM_PIN;
+
+static void uicc_pin_prompt_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_passwd_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *)local_sim);
+
+ unsigned char lock_type = -1;
+ GIsiSubBlockIter iter;
+ uint8_t status = UICC_STATUS_UNKNOWN;
+ uint8_t pin_attempts = -1;
+ uint8_t puk_attempts = -1;
+
+ if (!check_response_status(msg, UICC_PIN_RESP,
+ UICC_PIN_PROMPT_VERIFY) && !check_response_status(msg,
+ UICC_PIN_RESP, UICC_PIN_INFO))
+ goto error;
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ sd->pin_state_received = TRUE;
+ g_isi_msg_data_get_byte(msg, 2, &status);
+ } else if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_INFO)) {
+ uint8_t sbcount = 0;
+
+ sd->pin_state_received = TRUE;
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(
+ &iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_PIN_INFO:
+ g_isi_sb_iter_get_byte(&iter, &status, 4);
+ g_isi_sb_iter_get_byte(&iter,
+ &pin_attempts, 5);
+ g_isi_sb_iter_get_byte(&iter,
+ &puk_attempts, 6);
+ DBG("Status=%s, PIN attempts=%d, \
+ PUK attempts=%d",
+ uicc_status_name(status),
+ pin_attempts, puk_attempts);
+ break;
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+ }
+
+ if ((status == UICC_STATUS_OK) ||
+ (status == UICC_STATUS_PIN_ENABLED)) {
+ /* PIN query on, indication should tell
+ * if it is verified or not
+ */
+ if (pin_attempts == 0) {
+ DBG("PIN blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ } else {
+ DBG("PIN query enabled");
+ update_locked_pin(local_sim,
+ UICC_PIN_VERIFY_NEEDED,
+ sd->current_pin_id);
+ }
+
+ lock_type = local_sim->pin_type;
+ } else if (status == UICC_STATUS_PIN_DISABLED) {
+ if (pin_attempts == 0) {
+ DBG("PIN blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ lock_type = local_sim->pin_type;
+ } else {
+ DBG("PIN query disabled");
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] =
+ FALSE;
+ local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] =
+ FALSE;
+ lock_type = OFONO_SIM_PASSWORD_NONE;
+ }
+ }
+
+ if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
+ uicc_pin_prompt(cbd->user,
+ passwd_type_for_query,
+ cb,
+ cbd->data,
+ UICC_PIN_INFO);
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
+ return;
+error:
+ DBG("PIN prompt verify failed");
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ ofono_sim_passwd_cb_t cb,
+ void *data,
+ uint8_t service)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ int8_t index;
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+ DBG("PINID = %02x", sd->current_pin_id);
+
+ if ((cbd) && (sd) && (sd->current_pin_id)) {
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_PIN_REF >> 8,
+ UICC_SB_PIN_REF & 0xff,
+ 0, /*Sub block length.*/
+ 8,
+ sd->current_pin_id, /*PIN ID*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0 /*Filler*/
+ };
+ g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
+ SIM_TIMEOUT, uicc_pin_prompt_resp, cbd,
+ g_free);
+ } else {
+ DBG("PIN info query failed");
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ g_free(cbd);
+ }
+}
+
+static void uicc_passwd_state_query(struct ofono_sim *sim,
+ ofono_sim_passwd_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct ofono_sim_local *local_sim = (struct ofono_sim_local *)sim;
+
+ if (sd->pin_state_received) {
+ int lock_type = OFONO_SIM_PASSWORD_NONE;
+
+ if (sd->passwd_required) {
+ /* These should be in priority order, highest last */
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PIN;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PIN2] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PIN2;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PIN] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_PHNET_PIN;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PUK;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_SIM_PUK2] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_SIM_PUK2;
+
+ if (local_sim->locked_pins[
+ OFONO_SIM_PASSWORD_PHNET_PUK] == TRUE)
+ lock_type = OFONO_SIM_PASSWORD_PHNET_PUK;
+ }
+
+ DBG("UICC lock type=%d", lock_type);
+ CALLBACK_WITH_SUCCESS(cb, lock_type, data);
+ } else {
+ if (sd->uicc_app_started) {
+ /* No indication received but UICC app is
+ * started, let's query the state
+ */
+ DBG("Querying PIN info");
+ uicc_pin_prompt(sim, passwd_type_for_query,
+ cb, data, UICC_PIN_PROMPT_VERIFY);
+ return;
+ }
+
+ DBG("No UICC_PIN_IND received");
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+ }
+}
+
+static void uicc_pin_enable_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_DISABLE) &&
+ !check_response_status(msg, UICC_PIN_RESP,
+ UICC_PIN_ENABLE))
+ goto error;
+
+ DBG("PIN lock/unlock succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ DBG("PIN lock/unlock failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void uicc_pin_enable(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ int enable, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+ int8_t index;
+ unsigned char service = 0;
+ sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+
+ DBG("Lock=%d, PIN code=%s, PIN ID =%d",
+ enable, passwd, sd->current_pin_id);
+ if (enable) {
+ DBG("Enabling PIN");
+ service = UICC_PIN_ENABLE;
+ } else {
+ DBG("Disabling PIN");
+ service = UICC_PIN_DISABLE;
+ }
+ if ((cbd) && (sd) && (sd->current_pin_id)) {
+
+ unsigned char pinlen = strlen(passwd);
+
+ unsigned char msg[] = {
+ UICC_PIN_REQ,
+ service,
+ sd->app_id,
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 0, /*Filler*/
+ 1, /*number of subblocks*/
+ /* Subblock 1 */
+ UICC_SB_PIN >> 8,
+ UICC_SB_PIN & 0xff,
+ 0,
+ 16, /*Max length*/
+ sd->current_pin_id, /* PIN id */
+ UICC_PIN_OLD, /* PIN qualifier */
+ pinlen, /* PIN length */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+ memmove(&msg[14], passwd, pinlen);
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_pin_enable_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("Error");
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+ return;
+}
+
+static void uicc_pin_change_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_sim_local *local_sim =
+ (struct ofono_sim_local *) cbd->user;
+ struct sim_data *sd =
+ ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+ GIsiSubBlockIter iter;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_CHANGE))
+ goto error;
+
+ DBG("PIN change succeeded");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ return;
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
+ DBG("Authentication method blocked");
+ update_locked_pin(local_sim,
+ UICC_PIN_UNBLOCK_NEEDED,
+ sd->current_pin_id);
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ DBG("PIN change failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->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)
+{
+ 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 uicc_pin_send_puk_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;
+ uint8_t sbcount = 0;
+
+ if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_UNBLOCK))
+ goto error;
+
+ 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;
+
+error:
+ g_isi_msg_data_get_byte(msg, 5, &sbcount);
+ g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
+
+ while (g_isi_sb_iter_is_valid(&iter)) {
+ DBG("Sub-block %s",
+ uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+ switch (g_isi_sb_iter_get_id(&iter)) {
+ case UICC_SB_STATUS_WORD: {
+ uint16_t status;
+ g_isi_sb_iter_get_word(&iter, &status, 6);
+ DBG("APDU status word = %04X", status);
+
+ switch (status) {
+ case 0x6983:
+ case 0x9840:
+ DBG("Authentication method blocked");
+ break;
+ default:
+
+ if ((status & 0xfff0) == 0x63c0)
+ DBG("Attempts left %d", status & 0xf);
+
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_isi_sb_iter_next(&iter);
+ }
+
+ DBG("PIN reset failed");
+ CALLBACK_WITH_FAILURE(cb, cbd->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);
+ sd->current_pin_id = sd->pin1_id; /* No way to reset PIN2 */
+ DBG("PUK=%s, PIN=%s, PINID=%02x", puk, passwd, sd->current_pin_id);
+
+ if (cbd && sd) {
+ unsigned char service = UICC_PIN_UNBLOCK;
+ unsigned char pinlen = strlen(passwd);
+
+ 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_NEW, /* PIN qualifier*/
+ pinlen, /* PIN length*/
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ /* Subblock 2*/
+ UICC_SB_PUK >> 8,
+ UICC_SB_PUK & 0xff,
+ 0,
+ 16, /*Sub block length*/
+ sd->current_pin_id, /* PIN id*/
+ 8, /* PUK length*/
+ puk[0],
+ puk[1],
+ puk[2],
+ puk[3],
+ puk[4],
+ puk[5],
+ puk[6],
+ puk[7],
+ 0,
+ 0
+ };
+
+ if ((pinlen < 4) || (pinlen > 8))
+ goto error;
+
+ if (strlen(puk) != 8)
+ goto error;
+ memmove(&msg[14], passwd, pinlen);
+ g_isi_client_send_with_timeout(
+ sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+ uicc_pin_send_puk_resp, cbd, g_free);
+ return;
+ }
+
+error:
+ DBG("PIN reset error");
+ CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
+ return;
+}
+
static void isi_sim_register(struct ofono_sim *sim)
{
struct sim_data *sd = ofono_sim_get_data(sim);
@@ -414,34 +2504,121 @@ 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;
- if (!g_isi_msg_data_get_byte(msg, 0, &status))
+ 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);
+
+ 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;
+
+ uicc_sim = 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);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ sd->client = sd->secondary;
+
/* 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 +2631,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 = get_pn_uicc_client(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;
}
@@ -472,12 +2665,19 @@ static void isi_sim_remove(struct ofono_sim *sim)
{
struct sim_data *data = ofono_sim_get_data(sim);
- ofono_sim_set_data(sim, NULL);
-
if (data == NULL)
return;
- g_isi_client_destroy(data->client);
+ if (g_isi_client_resource(data->client) == PN_UICC) {
+ data->uicc_app_started = FALSE;
+ data->pin_state_received = FALSE;
+ data->passwd_required = TRUE;
+
+ pn_uicc_client_destroy(data->client);
+ } else
+ g_isi_client_destroy(data->client);
+
+ ofono_sim_set_data(sim, NULL);
g_free(data);
}
@@ -493,8 +2693,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);
@@ -504,3 +2714,24 @@ void isi_sim_exit(void)
{
ofono_sim_driver_unregister(&driver);
}
+
+GIsiClient *get_pn_uicc_client(GIsiModem *modem, uint8_t resource)
+{
+ if (pn_uicc_client == NULL)
+ pn_uicc_client = g_isi_client_create(modem, resource);
+
+ uicc_users++;
+ return pn_uicc_client;
+}
+
+void pn_uicc_client_destroy(GIsiClient *client)
+{
+ if (uicc_users > 0)
+ uicc_users--;
+ if (!uicc_users) {
+ if (pn_uicc_client) {
+ g_isi_client_destroy(client);
+ pn_uicc_client = NULL;
+ }
+ }
+}
diff --git a/drivers/isimodem/uicc.h b/drivers/isimodem/uicc.h
new file mode 100644
index 0000000..4be4d01
--- /dev/null
+++ b/drivers/isimodem/uicc.h
@@ -0,0 +1,268 @@
+/*
+ * 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
+};
+
+int get_app_id(void);
+int get_app_type(void);
+int get_client_id(void);
+
+GIsiClient *read_pn_uicc_client(void); /* Only returns the exisisting client */
+
+GIsiClient *get_pn_uicc_client(GIsiModem *modem, uint8_t resource);
+
+void pn_uicc_client_destroy(GIsiClient *client);
+
+struct ofono_sim_driver *get_sim_driver_func(void);
+
+struct ofono_sim *get_sim(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_UICC_H */
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH 08/18] isimodem: UICC sim support for wgmodem2.5
2011-02-15 12:31 ` [PATCH 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
@ 2011-02-17 13:55 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-17 13:55 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 102560 bytes --]
Hi,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
(snip)
> diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
> index bfecbc9..0ef02f3 100644
> --- a/drivers/isimodem/sim.c
> +++ b/drivers/isimodem/sim.c
> @@ -3,6 +3,7 @@
> * oFono - Open Source Telephony
> *
> * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
> + * Copyright (C) ST-Ericsson SA 2011.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -33,24 +34,216 @@
>
> #include <gisi/message.h>
> #include <gisi/client.h>
> +#include <gisi/iter.h>
>
> #include <ofono/log.h>
> #include <ofono/modem.h>
> #include <ofono/sim.h>
> -#include "simutil.h"
> +#include <ofono/dbus.h>
>
> +#include "simutil.h"
> #include "isimodem.h"
> #include "isiutil.h"
> #include "sim.h"
> +#include "uicc.h"
> #include "debug.h"
>
> -#define SIM_MAX_SPN_LENGTH 16
> +#define PIN_PROMPT
> +#define STATUS_WORD_HANDLING
> +
> +#define SIM_MAX_SPN_LENGTH 16
> +#define CLIENT_ID 1
> +
> +
> +/* File info parameters */
> +#define FCP_TEMPLATE 0x62
> +#define FCP_FILE_SIZE 0x80
> +#define FCP_FILE_DESC 0x82
> +#define FCP_FILE_ID 0x83
> +#define FCP_FILE_LIFECYCLE 0x8A
> +#define FCP_FILE_SECURITY_ARR 0x8B
> +#define FCP_FILE_SECURITY_COMPACT 0x8C
> +#define FCP_FILE_SECURITY_EXPANDED 0xAB
> +#define FCP_PIN_STATUS 0xC6
This should be an enum.
> +#define SIM_EFARR_FILEID 0x6F06
Why is this not in simutil.h?
> +#define ADF_USIM 0x7FFF
> +#define MAX_SIM_APPS 10
> +#define NOT_AVAILABLE -1
> +#define NOT_ACTIVATED -1
>
> struct sim_data {
> GIsiClient *client;
> + GIsiClient *primary;
> + GIsiClient *secondary;
> + gboolean iccid;
> gboolean registered;
> + gboolean uicc_app_started;
> + gboolean pin_state_received;
> + gboolean passwd_required;
> + int app_id;
> + int trying_app_id;
> + int app_type;
> + int trying_app_type;
> + uint8_t client_id;
> + uint8_t current_pin_id;
> + uint8_t pin1_id;
> + uint8_t pin2_id;
> +};
> +
> +struct ofono_sim_local {
> + char *iccid;
> + char *imsi;
> + enum ofono_sim_phase phase;
> + unsigned char mnc_length;
> + GSList *own_numbers;
> + GSList *new_numbers;
> + GSList *service_numbers;
> + gboolean sdn_ready;
> + enum ofono_sim_state state;
> + enum ofono_sim_password_type pin_type;
> + gboolean locked_pins[OFONO_SIM_PASSWORD_INVALID];
> + char **language_prefs;
> + GQueue *simop_q;
> + gint simop_source;
> + unsigned char efmsisdn_length;
> + unsigned char efmsisdn_records;
> + unsigned char *efli;
> + unsigned char efli_length;
> + enum ofono_sim_cphs_phase cphs_phase;
> + unsigned char cphs_service_table[2];
> + struct ofono_watchlist *state_watches;
> + const struct ofono_sim_driver *driver;
> + void *driver_data;
> + struct ofono_atom *atom;
> + DBusMessage *pending;
> +};
> +
> +struct sim_passwd_to_pin_id {
> + uint8_t passwd_type;
> + uint8_t pin_id;
> +};
> +
> +static struct sim_passwd_to_pin_id const pin_ids[] = {
> + {OFONO_SIM_PASSWORD_NONE, 0},
> + {OFONO_SIM_PASSWORD_SIM_PIN, 1},
> + {OFONO_SIM_PASSWORD_PHSIM_PIN, 0},
> + {OFONO_SIM_PASSWORD_PHFSIM_PIN, 0},
> + {OFONO_SIM_PASSWORD_SIM_PIN2, -1},
> + {OFONO_SIM_PASSWORD_PHNET_PIN, 0x11},
> + {OFONO_SIM_PASSWORD_PHNETSUB_PIN, 0},
> + {OFONO_SIM_PASSWORD_PHSP_PIN, 0},
> + {OFONO_SIM_PASSWORD_PHCORP_PIN, 0},
> + {OFONO_SIM_PASSWORD_SIM_PUK, -1},
> + {OFONO_SIM_PASSWORD_PHFSIM_PUK, 0},
> + {OFONO_SIM_PASSWORD_SIM_PUK2, -1},
> + {OFONO_SIM_PASSWORD_PHNET_PUK, 0},
> + {OFONO_SIM_PASSWORD_PHNETSUB_PUK, 0},
> + {OFONO_SIM_PASSWORD_PHSP_PUK, 0},
> + {OFONO_SIM_PASSWORD_PHCORP_PUK, 0},
> + {OFONO_SIM_PASSWORD_INVALID, 0}
> +};
I don't like you mixing hex and decimal values, and above all, some of
these are also assigning signed values to an unsigned variable.
> +
> +const uint8_t upin_id = 0x11;
> +
> +/* Current SIM */
> +static struct ofono_sim *uicc_sim;
> +/* UICC client */
> +static GIsiClient *pn_uicc_client;
> +static int uicc_users;
I doubt this is going to work.
So what happens when someone plugs in two isimodems into the system?
Is there a specific reason that the UICC client needs to be shared
among the rest of the drivers? Why can't each of them just create
their own instance, and let the gisi modem handle the client reuse
optimizations.
> +
> +struct sim_applications {
> + int app_list[MAX_SIM_APPS];
> + int app_type[MAX_SIM_APPS];
> +};
> +
> +struct sim_applications *sim_application_list_p;
Is this a global list, or a per-modem list?
> +struct file_info {
> + int fileid;
> + int length;
> + int structure;
> + int record_length;
> + uint8_t access[3];
> + uint8_t file_status;
> +};
> +
> +static struct file_info const static_file_info[] = {
> + {
> + SIM_EFSPN_FILEID, 17, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 0, { 0x0e, 0xff, 0xee }
> + },
> + {
> + SIM_EF_ICCID_FILEID, 10, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 10, { 0x0f, 0xff, 0xee }
> + },
> + {
> + SIM_EFPL_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 1, { 0x0f, 0xff, 0xff }
> + }, /* not found */
> + {
> + SIM_EFLI_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 1, { 0x0f, 0xff, 0xff }
> + }, /* not found */
> + {
> + SIM_EFMSISDN_FILEID, 28, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 28, { 0x01, 0xff, 0xee }
> + },
> + {
> + SIM_EFAD_FILEID, 20, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 20, { 0x0e, 0xff, 0xee }
> + },
> + {
> + SIM_EFPHASE_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 1, { 0x0e, 0xff, 0xee }
> + },
> + {
> + SIM_EFPNN_FILEID, 4 * 18, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 18, { 0x0e, 0xff, 0xee }
> + }, /* 4 records, name 16 bytes */
> + {
> + SIM_EFOPL_FILEID, 4 * 24, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 24, { 0x0e, 0xff, 0xee }
> + }, /* 4 records, name 16 bytes */
> + {
> + SIM_EFMBI_FILEID, 5, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 5, { 0x0e, 0xff, 0xee }
> + },
> + {
> + SIM_EFMWIS_FILEID, 6, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 6, { 0x01, 0xff, 0xee }
> + },
> + {
> + SIM_EFSPDI_FILEID, 64, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 64, { 0x0e, 0xff, 0xee }
> + },
> + {
> + SIM_EFECC_FILEID, 5 * 3, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 3, { 0x0e, 0xff, 0xee }
> + }, /* Can be also FIXED in 3G */
> + {
> + SIM_EFCBMIR_FILEID, 8 * 4, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 4, { 0x01, 0xff, 0xee }
> + }, /* 8 records */
> + {
> + SIM_EFCBMI_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 2, { 0x01, 0xff, 0xee }
> + }, /* 8 records */
> + {
> + SIM_EFCBMID_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 2, { 0x01, 0xff, 0x11 }
> + }, /* 8 records */
> + {
> + SIM_EFSMSP_FILEID, 56, OFONO_SIM_FILE_STRUCTURE_FIXED,
> + 56, { 0x01, 0xff, 0xee }
> + },
> + {
> + SIM_EFIMSI_FILEID, 9, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
> + 9, { 0x0e, 0xff, 0xee }
> + },
> };
>
> +static uint8_t get_sfi(const int fileid);
> +
This doesn't need forward declaration. Just put the implementation
here. However, I would rename this to something like
fileid_to_short_fileid()
> struct sim_imsi {
> uint8_t length;
> uint8_t imsi[8];
> @@ -66,14 +259,283 @@ struct sim_spn {
> uint8_t disp_roam;
> };
>
> -struct file_info {
> - int fileid;
> - int length;
> - int structure;
> - int record_length;
> - uint8_t access[3];
> - uint8_t file_status;
> -};
> +static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
> + struct sim_data *sd,
> + uint16_t *length,
> + uint16_t *record_length,
> + uint8_t *records,
> + uint8_t *structure);
> +
> +static void uicc_pin_prompt(struct ofono_sim *sim,
> + enum ofono_sim_password_type passwd_type,
> + ofono_sim_passwd_cb_t cb,
> + void *data,
> + uint8_t service);
> +
> +static void uicc_application_activate_req(GIsiClient *client,
> + void *opaque,
> + unsigned char appl_type,
> + unsigned char aid);
> +
Forward declarations should be avoided if at all possible.
> +static int sim_applications_get_next_index(struct sim_applications *sa,
> + int current_app)
> +{
> + if (current_app < (MAX_SIM_APPS - 1)) {
> + int i;
> +
> + for (i = ++current_app; i < MAX_SIM_APPS; i++) {
> + if (sa->app_list[i] &&
> + (sa->app_type[i] != UICC_APPL_TYPE_UNKNOWN))
Empty line before the if, and if the statement spans multiple lines,
every new line needs an extra indentation.
> + return i;
> + }
> + }
> +
> + return NOT_AVAILABLE;
> +}
I would refactor this function to return early, if the current_app is
out of range, and not the other way around.
> +static uint8_t get_pin_id(struct sim_data *sd,
> + uint8_t passwd_type,
> + int8_t *index)
> +{
> + const uint16_t MAX_INDEX = (sizeof(pin_ids)/sizeof(
> + struct sim_passwd_to_pin_id));
> + uint8_t i, pin_id;
> + *index = -1;
> +
> + for (i = 0; i < MAX_INDEX; i++) {
> + if (pin_ids[i].passwd_type == passwd_type)
> + *index = i;
> + }
> +
> + switch (passwd_type) {
> + case OFONO_SIM_PASSWORD_SIM_PIN:
> + case OFONO_SIM_PASSWORD_SIM_PUK:
> + return sd->pin1_id;
> + case OFONO_SIM_PASSWORD_SIM_PIN2:
> + case OFONO_SIM_PASSWORD_SIM_PUK2:
> + return sd->pin2_id;
> + default:
> +
> + if (*index == -1)
> + pin_id = 0;
> + else
> + pin_id = pin_ids[*index].pin_id;
> +
> + return pin_id;
> + }
> +}
> +
> +static void update_locked_pin(struct ofono_sim_local *local_sim,
> + uint8_t lock_type, uint8_t pinID)
> +{
> + struct sim_data *sd = ofono_sim_get_data((struct ofono_sim *)local_sim);
> +
> + switch (lock_type) {
> + case UICC_PIN_VERIFY_NEEDED:
> +
> + if (pinID <= sd->pin1_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_SIM_PIN;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
> + sd->passwd_required = TRUE;
> + } else if (pinID == sd->pin2_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_SIM_PIN2;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PIN2] = TRUE;
> + sd->passwd_required = TRUE;
> + } else if (pinID == upin_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_PHNET_PIN;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_PHNET_PIN] = TRUE;
> + sd->passwd_required = TRUE;
> + }
> +
> + break;
> + case UICC_PIN_UNBLOCK_NEEDED:
> +
> + if (pinID == sd->pin1_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_SIM_PUK;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PUK] = TRUE;
> + sd->passwd_required = TRUE;
> + } else if (pinID == sd->pin2_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_SIM_PUK2;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PUK2] = TRUE;
> + sd->passwd_required = TRUE;
> + } else if (pinID == upin_id) {
> + local_sim->pin_type =
> + OFONO_SIM_PASSWORD_PHNET_PUK;
> + local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_PHNET_PUK] = TRUE;
> + sd->passwd_required = TRUE;
> + }
> +
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static gboolean get_fileid_path(struct ofono_sim *sim,
> + int *mf_path,
> + int *df1_path,
> + int *df2_path,
> + unsigned char *df_len,
> + int fileid)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + switch (fileid) {
> + case SIM_EFPL_FILEID:
> + case SIM_EF_ICCID_FILEID:
> + *mf_path = SIM_MF_FILEID;
> + *df1_path = 0x0000;
> + *df2_path = 0x0000;
> + *df_len = 2;
> + break;
> + case SIM_EFSMSP_FILEID:
> + case SIM_EFSDN_FILEID:
> + case SIM_EFMSISDN_FILEID:
> + *mf_path = SIM_MF_FILEID;
> +
> + if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
> + *df1_path = SIM_DFTELECOM_FILEID;
> + else
> + *df1_path = ADF_USIM;
> +
> + *df2_path = 0x0000;
> + *df_len = 4;
> + break;
> + case SIM_EFLI_FILEID:
> + case SIM_EFSPN_FILEID:
> + case SIM_EFAD_FILEID:
> + case SIM_EFPNN_FILEID:
> + case SIM_EFOPL_FILEID:
> + case SIM_EFMBDN_FILEID:
> + case SIM_EFMBI_FILEID:
> + case SIM_EFMWIS_FILEID:
> + case SIM_EFSPDI_FILEID:
> + case SIM_EFECC_FILEID:
> + case SIM_EFCBMI_FILEID:
> + case SIM_EFCBMIR_FILEID:
> + case SIM_EFCBMID_FILEID:
> + case SIM_EFIMSI_FILEID:
> + case SIM_EFPHASE_FILEID: /* 3GPP TS 11.11 */
> + case SIM_EFARR_FILEID:
> + case SIM_EF_CPHS_INFORMATION_FILEID:
> + *mf_path = SIM_MF_FILEID;
> +
> + if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
> + *df1_path = SIM_DFGSM_FILEID;
> + else
> + *df1_path = ADF_USIM;
> +
> + *df2_path = 0x0000;
> + *df_len = 4;
> + break;
> + /* No info */
> + case SIM_EF_CPHS_MBDN_FILEID:
> + case SIM_EF_CPHS_MWIS_FILEID:
> + DBG("======== No path info for %04X", fileid);
> + return FALSE;
> + case SIM_EFADN_FILEID: /* Only for SIM */
> + case SIM_EFEXT1_FILEID: /* Only for SIM */
> + *mf_path = SIM_MF_FILEID;
> + *df1_path = SIM_DFTELECOM_FILEID;
> + *df2_path = 0x0000;
> + *df_len = 4;
> + break;
> + default:
> + *mf_path = SIM_MF_FILEID;
> + *df1_path = SIM_DFTELECOM_FILEID;
> + *df2_path = SIM_DFPHONEBOOK_FILEID;
> + *df_len = 6;
> + break;
> + }
> +
> + return TRUE;
> +}
> +
> +static uint8_t get_sfi(const int fileid)
> +{
> + uint8_t ret;
> +
> + /* SFI list from 3GPP TS 31.102 Annex H */
> + switch (fileid) {
> + case SIM_EFECC_FILEID:
> + ret = 01;
> + break;
> + case SIM_EFLI_FILEID:
> + ret = 02;
> + break;
> + case SIM_EFAD_FILEID:
> + ret = 03;
> + break;
> + case SIM_EFIMSI_FILEID:
> + ret = 07;
> + break;
> + case SIM_EFCBMID_FILEID:
> + ret = 0x0E;
> + break;
> + case SIM_EFPNN_FILEID:
> + ret = 0x19;
> + break;
> + case SIM_EFOPL_FILEID:
> + ret = 0x1A;
> + break;
> + default:
> + ret = UICC_SFI_NOT_PRESENT;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +int get_app_id(void)
> +{
> + if (uicc_sim) {
> + struct sim_data *sd = ofono_sim_get_data(uicc_sim);
> + DBG("app_id %d", sd->app_id);
> + return sd->app_id;
> + } else
> + return -1;
> +}
> +
> +int get_app_type(void)
> +{
> + if (uicc_sim) {
> + struct sim_data *sd = ofono_sim_get_data(uicc_sim);
> + DBG("app_type %d", sd->app_type);
> + return sd->app_type;
> + } else
> + return -1;
> +}
> +
> +int get_client_id(void)
> +{
> + if (uicc_sim) {
> + struct sim_data *sd = ofono_sim_get_data(uicc_sim);
> + DBG("client_id %d", sd->client_id);
> + return sd->client_id;
> + } else
> + return -1;
> +}
> +
> +GIsiClient *read_pn_uicc_client(void)
> +{
> + return pn_uicc_client;
> +}
> +
> +struct ofono_sim *get_sim(void)
> +{
> + return uicc_sim;
> +}
How is this API supposed to be used (presumably) by other drivers?
At a minimum, you should keep track of all of the modem references,
and have the other drivers give you their modem reference as a lookup
key.
> /* Returns file info */
> static gboolean fake_file_info(gpointer user)
> @@ -89,29 +551,6 @@ static gboolean fake_file_info(gpointer user)
> return FALSE;
> }
>
> -static void isi_read_file_info(struct ofono_sim *sim, int fileid,
> - ofono_sim_file_info_cb_t cb, void *data)
> -{
> - int i;
> - static struct file_info const info[] = {
> - { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
> - { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
> - };
> - int N = sizeof(info) / sizeof(info[0]);
> - struct isi_cb_data *cbd;
> -
> - for (i = 0; i < N; i++) {
> - if (fileid == info[i].fileid) {
> - cbd = isi_cb_data_new((void *) &info[i], cb, data);
> - g_idle_add(fake_file_info, cbd);
> - return;
> - }
> - }
> -
> - DBG("Fileid %04X not implemented", fileid);
> - CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
> -}
> -
> static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
> uint8_t service)
> {
> @@ -129,7 +568,10 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
> return FALSE;
> }
>
> - if (!g_isi_msg_data_get_byte(msg, 1, &cause) || cause != SIM_SERV_OK) {
> + if ((!g_isi_msg_data_get_byte(msg, 1, &cause) ||
> + cause != SIM_SERV_OK) &&
> + (!g_isi_msg_data_get_byte(msg, 2, &cause) ||
> + cause != UICC_STATUS_OK)) {
PN_UICC has two different causes?
> DBG("Request failed: %s", sim_isi_cause_name(cause));
> return FALSE;
> }
> @@ -141,6 +583,303 @@ static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid,
> return TRUE;
> }
>
> +static void handle_app_uicc_usim(GIsiSubBlockIter *iter,
> + struct sim_data *sd,
> + uint16_t *length,
> + uint16_t *record_length,
> + uint8_t *records, uint8_t *structure)
> +{
> + uint8_t fcp;
> + uint8_t fcp_len;
> + uint8_t read = 0;
> + uint8_t id;
> + uint8_t item_len;
> + uint16_t file_id;
> + uint8_t desc;
> + uint8_t coding;
> + uint8_t pin_do_len;
> + uint8_t pin_len;
> + uint8_t pin_tag;
> + uint8_t pin_id;
> + uint8_t pin_tag_pos;
> +
> +
> + (void)g_isi_sb_iter_get_byte(iter, &fcp, 8);
That cast is not necessary, but you should really check the return value.
> + if (fcp == FCP_TEMPLATE) {
Reduces indentation a lot, if you check that fcp != FCP_TEMPLATE, and
goto some 'out' label.
> + (void) g_isi_sb_iter_get_byte(iter, &fcp_len, 9);
> + while (read < fcp_len) {
> + (void) g_isi_sb_iter_get_byte(iter, &id, read + 10);
> + (void) g_isi_sb_iter_get_byte(iter, &item_len,
> + read + 11);
> +
> + switch (id) {
> + case FCP_FILE_SIZE:
> + if (item_len == 2) {
> + g_isi_sb_iter_get_word(iter, length,
> + read + 10 + 2);
> + }
> + break;
> + case FCP_FILE_ID:
> +
> + if (item_len == 2) {
> + g_isi_sb_iter_get_word(iter, &file_id,
> + read + 10 + 2);
> + }
> + break;
> + case FCP_FILE_DESC:
> + if (item_len >= 2) {
> + g_isi_sb_iter_get_byte(iter, &desc,
> + read + 10 + 2);
> + g_isi_sb_iter_get_byte(iter, &coding,
> + read + 10 + 3);
> + }
> +
> + if (item_len >= 4) {
> + g_isi_sb_iter_get_word(iter,
> + record_length,
> + read + 10 + 4);
> + g_isi_sb_iter_get_byte(iter, records,
> + read + 10 + 6);
> + }
> + break;
> + case FCP_PIN_STATUS:
> + g_isi_sb_iter_get_byte(iter, &pin_do_len,
> + read + 10 + 3);
> + pin_tag_pos = read + 10 + 4 + pin_do_len;
> + g_isi_sb_iter_get_byte(iter, &pin_tag,
> + pin_tag_pos);
> +
> + while (pin_tag == 0x83) {
> +
> + g_isi_sb_iter_get_byte(iter, &pin_len,
> + pin_tag_pos + 1);
> + g_isi_sb_iter_get_byte(iter, &pin_id,
> + pin_tag_pos + 2);
> +
> + pin_tag_pos += 2 + pin_len;
> + g_isi_sb_iter_get_byte(iter, &pin_tag,
> + pin_tag_pos);
> +
> + if ((0x01 <= pin_id) &&
> + (pin_id <= 0x08))
> + sd->pin1_id = pin_id;
> + else if ((0x81 <= pin_id) &&
> + (pin_id <= 0x88))
> + sd->pin2_id = pin_id;
> + read += item_len + 2;
> + }
> + break;
> + case FCP_FILE_SECURITY_ARR:
> + case FCP_FILE_SECURITY_COMPACT:
> + case FCP_FILE_SECURITY_EXPANDED:
> +
> + /* Not implemented, using
> + * static access rules as these
> + * are used only for caching
> + * See ETSI TS 102 221, ch
> + * 11.1.1.4.7 and
> + * Annexes E,F and G
> + */
> + case FCP_FILE_LIFECYCLE:
> + default:
> + DBG("FCP id %02X not supported", id);
> + break;
> + }
> +
> + /*Data length + id size + len size */
> + read += item_len + 2;
> + }
> + }
> + if ((desc & 7) == 1)
> + *structure = OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
> + else if ((desc & 7) == 2)
> + *structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
> + else if ((desc & 7) == 6)
> + *structure = OFONO_SIM_FILE_STRUCTURE_CYCLIC;
> +}
> +
> +static void isi_file_info_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_file_info_cb_t cb = cbd->cb;
> + uint16_t length = 0;
> + uint16_t record_length = 0;
> + uint8_t structure = -1;
> + uint8_t records = 0;
> + uint16_t file_id = 0;
> + uint8_t access[3] = {0, 0, 0};
> + uint8_t item_len = 0;
> + gboolean everything_ok = FALSE;
> + /*Access is read from static file info*/
> + struct file_info const *info = cbd->user;
> + GIsiSubBlockIter iter;
> + struct sim_data *sd = ofono_sim_get_data(uicc_sim);
> + uint8_t sbcount = 0;
> +
> + if (!check_response_status(msg, UICC_APPL_CMD_RESP,
> + UICC_APPL_FILE_INFO))
> + goto error;
> +
> + if (info != NULL) {
> + access[0] = info->access[0];
> + access[1] = info->access[1];
> + access[2] = info->access[2];
> + }
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_FCI:
> + DBG("UICC_SB_FCI");
> + everything_ok = TRUE;
> +
> + switch (sd->app_type) {
> + case UICC_APPL_TYPE_UICC_USIM:
> + DBG("UICC_APPL_TYPE_UICC_USIM");
> + handle_app_uicc_usim(&iter, sd,
> + &length, &record_length,
> + &records, &structure);
> +
> + break;
> + case UICC_APPL_TYPE_ICC_SIM:
> + DBG("UICC_APPL_TYPE_ICC_SIM");
> + g_isi_sb_iter_get_word(&iter, &length, 10);
> + g_isi_sb_iter_get_word(&iter, &file_id, 12);
> + (void)g_isi_sb_iter_get_byte(&iter,
> + &access[0],
> + 16);
> + (void)g_isi_sb_iter_get_byte(&iter,
> + &access[0],
> + 17);
> + (void)g_isi_sb_iter_get_byte(&iter,
> + &access[0],
> + 18);
> + (void)g_isi_sb_iter_get_byte(&iter,
> + &item_len, 20);
> + (void)g_isi_sb_iter_get_byte(&iter,
> + &structure,
> + 21);
> +
> + if (item_len == 2)
> + (void)g_isi_sb_iter_get_byte(&iter,
> + (uint8_t *)&record_length,
> + 22);
> +
> + break;
> + default:
> + DBG("UICC application type %d not supported",
> + sd->app_type);
> + break;
> + }
> +
> + break;
> + default:
> + DBG("Skipping SB");
> + break;
> + }
> +
> + if (g_isi_sb_iter_next(&iter) == FALSE)
> + goto error;
> + }
> +
> + if (everything_ok) {
> + CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
> + access, '\n', cbd->data);
> + return;
> + }
> +
> +error:
> + DBG("Error reading file info");
> + CALLBACK_WITH_FAILURE(cb, 0, 0, 0, access, '\n', cbd->data);
> +}
> +
> +static void isi_read_file_info(struct ofono_sim *sim, int fileid,
> + ofono_sim_file_info_cb_t cb, void *data)
> +{
> + int i;
> + static struct file_info const info[] = {
> + { SIM_EFSPN_FILEID, 17, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
> + { SIM_EF_ICCID_FILEID, 10, 0, 0, { 0x0f, 0xff, 0xff }, 1 },
> + };
> + int N = sizeof(info) / sizeof(info[0]);
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd;
> +
> + if ((sd != NULL) && g_isi_client_resource(sd->client) == PN_UICC) {
> + /* Prepare for static file info used for access rights */
> + int i;
> + int mf_path = 0;
> + int df1_path = 0;
> + int df2_path = 0;
> + unsigned char df_len = 0;
> +
> + N = sizeof(static_file_info) / sizeof(static_file_info[0]);
> + cbd = isi_cb_data_new(NULL, cb, data);
> + DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
> +
> + for (i = 0; i < N; i++) {
> + if (fileid == static_file_info[i].fileid &&
> + cbd != NULL) {
> + cbd->user = (void *) &static_file_info[i];
> + continue;
> + }
> + }
> + if (!get_fileid_path(sim, &mf_path, &df1_path,
> + &df2_path, &df_len, fileid)) {
> + g_free(cbd);
> + goto error;
> + }
> + if (cbd) {
> + const unsigned char msg[] = {
> + UICC_APPL_CMD_REQ,
> + UICC_APPL_FILE_INFO,
> + sd->app_id,
> + UICC_SESSION_ID_NOT_USED, /*Session ID*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 1, /*number of subblocks*/
> + /* Subblock 1*/
> + UICC_SB_APPL_PATH >> 8,
> + UICC_SB_APPL_PATH & 0xff,
> + 0,
> + 16, /*Sub block length*/
> + fileid >> 8, /* UICC elementary file ID*/
> + fileid & 0xFF,
> + get_sfi(fileid), /* Elementary file short id*/
> + 0, /*filler*/
> + df_len, /*DF Path length*/
> + 0, /*Filler*/
> + mf_path >> 8,
> + mf_path & 0xff,
> + df1_path >> 8, /*DF Path*/
> + df1_path & 0xFF,
> + df2_path >> 8, /*DF Path*/
> + df2_path & 0xFF,
> + };
> + g_isi_client_send(sd->client, msg, sizeof(msg),
> + isi_file_info_resp, cbd, g_free);
> + return;
> + }
> + } else {
> + for (i = 0; i < N; i++) {
> + if (fileid == info[i].fileid) {
> + cbd = isi_cb_data_new((void *) &info[i], cb,
> + data);
> + g_idle_add(fake_file_info, cbd);
> + return;
> + }
> + }
> +
> + }
> +error:
> + DBG("Fileid %04X not implemented", fileid);
> + CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
> +}
> +
> static void spn_resp_cb(const GIsiMessage *msg, void *data)
> {
> struct isi_cb_data *cbd = data;
> @@ -234,32 +973,142 @@ static gboolean isi_read_iccid(struct ofono_sim *sim, struct isi_cb_data *cbd)
> read_iccid_resp_cb, cbd, g_free);
> }
>
> +static void isi_read_file_transparent_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_read_cb_t cb = cbd->cb;
> + uint32_t filelen = 0;
> + unsigned char filedata[256] = { 0xff };
> + gboolean everything_ok = FALSE;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> +
> + if (!check_response_status(msg, UICC_APPL_CMD_RESP,
> + UICC_APPL_READ_TRANSPARENT))
> + goto error;
> +
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_FILE_DATA:
> + g_isi_sb_iter_get_dword(&iter, &filelen, 4);
> + memmove(&filedata, iter.start + 8, filelen);
> + everything_ok = TRUE;
> + break;
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +
> + if (everything_ok) {
> + DBG("Transparent EF read: 1st byte %02x, len %d",
> + filedata[0], filelen);
> + CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
> + return;
> + }
> +
> +error:
> + DBG("Error reading transparent EF");
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> +}
> +
> static void isi_read_file_transparent(struct ofono_sim *sim, int fileid,
> int start, int length,
> ofono_sim_read_cb_t cb, void *data)
> {
> + struct sim_data *sd = ofono_sim_get_data(sim);
> struct isi_cb_data *cbd;
> gboolean done;
>
> cbd = isi_cb_data_new(sim, cb, data);
> - if (cbd == NULL)
> +
> + if (cbd == NULL || sd == NULL)
> goto error;
>
> - switch (fileid) {
> - case SIM_EFSPN_FILEID:
> - done = isi_read_spn(sim, cbd);
> - break;
> + if (g_isi_client_resource(sd->client) == PN_UICC) {
> + int mf_path = 0;
> + int df1_path = 0;
> + int df2_path = 0;
> + unsigned char df_len = 0;
> +
> + DBG("File ID=%04X, client %d, AID %d",
> + fileid, sd->client_id, sd->app_id);
> +
> + if (get_fileid_path(sim, &mf_path, &df1_path,
> + &df2_path, &df_len, fileid)) {
> + const unsigned char msg[] = {
> + UICC_APPL_CMD_REQ,
> + UICC_APPL_READ_TRANSPARENT,
> + sd->app_id,
> + UICC_SESSION_ID_NOT_USED, /*Session ID*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 3, /*number of subblocks*/
> + /* Subblock 1 */
> + UICC_SB_CLIENT >> 8,
> + UICC_SB_CLIENT & 0xff,
> + 0,
> + 8, /*Sub block length*/
> + 0, 0, 0, /* Filler */
> + sd->client_id,
> + /* Subblock 2*/
> + UICC_SB_TRANSPARENT >> 8,
> + UICC_SB_TRANSPARENT & 0xff,
> + 0, /*Sub block length*/
> + 8, /*Sub block length*/
> + 0, /*File offset (0=beginning)*/
> + 0, /*File offset (0=beginning)*/
> + 0, /*Data amount (0=all)*/
> + 0, /*Data amount (0=all)*/
> + /* Subblock 3 */
> + UICC_SB_APPL_PATH >> 8,
> + UICC_SB_APPL_PATH & 0xff,
> + 0,
> + 16, /* Sub block length*/
> + fileid >> 8, /* UICC elementary file ID*/
> + fileid & 0xFF,
> + get_sfi(fileid),/*Elementary file short id*/
> + 0, /*filler*/
> + df_len, /*DF Path length*/
> + 0, /*Filler*/
> + mf_path >> 8,
> + mf_path & 0xff,
> + df1_path >> 8, /*DF Path*/
> + df1_path & 0xFF,
> + df2_path >> 8, /*DF Path*/
> + df2_path & 0xFF
> + };
> + g_isi_client_send_with_timeout(
> + sd->client, msg, sizeof(msg), SIM_TIMEOUT,
> + isi_read_file_transparent_resp, cbd, g_free);
> + return;
> + }
> + goto error;
>
> - case SIM_EF_ICCID_FILEID:
> - done = isi_read_iccid(sim, cbd);
> - break;
> + } else {
> + switch (fileid) {
> + case SIM_EFSPN_FILEID:
> + done = isi_read_spn(sim, cbd);
> + break;
>
> - default:
> - done = FALSE;
> - }
> + case SIM_EF_ICCID_FILEID:
> + done = isi_read_iccid(sim, cbd);
> + break;
>
> - if (done)
> - return;
> + default:
> + done = FALSE;
> + }
> +
> + if (done)
> + return;
> + }
>
> DBG("Fileid %04X not implemented", fileid);
>
> @@ -268,12 +1117,125 @@ error:
> g_free(cbd);
> }
>
> -static void isi_read_file_linear(struct ofono_sim *sim, int fileid,
> - int record, int length,
> - ofono_sim_read_cb_t cb, void *data)
> +static void isi_read_file_linear_fixed_resp(const GIsiMessage *msg, void *data)
> {
> - DBG("Fileid %04X not implemented", fileid);
> + struct isi_cb_data *cbd = data;
> + ofono_sim_read_cb_t cb = cbd->cb;
> + uint32_t filelen = 0;
> + unsigned char filedata[256] = { 0xff };
> + gboolean everything_ok = FALSE;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> +
> + if (!check_response_status(msg, UICC_APPL_CMD_RESP,
> + UICC_APPL_READ_LINEAR_FIXED))
> + goto error;
> +
> + everything_ok = FALSE;
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_FILE_DATA:
> + g_isi_sb_iter_get_dword(&iter, &filelen, 4);
> + memmove(&filedata, iter.start + 8, filelen);
> + everything_ok = TRUE;
> + break;
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +
> + if (everything_ok) {
> + DBG("Linear fixed EF read: 1st byte %02x, len %d",
> + filedata[0], filelen);
> + CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
> + return;
> + }
> +
> +error:
> + DBG("Error reading linear fixed EF");
> + CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
> +}
> +
> +static void isi_read_file_linear(struct ofono_sim *sim,
> + int fileid,
> + int record,
> + int rec_length,
> + ofono_sim_read_cb_t cb,
> + void *data)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> + int mf_path = 0;
> + int df1_path = 0;
> + int df2_path = 0;
> + unsigned char df_len = 0;
> + DBG("File ID=%04X, record %d, client %d AID %d",
> + fileid, record, sd->client_id, sd->app_id);
> + if (!get_fileid_path(sim, &mf_path,
> + &df1_path, &df2_path, &df_len, fileid))
> + goto error;
> + if ((cbd != NULL) && (sd != NULL)) {
> +
> + const unsigned char msg[] = {
> + UICC_APPL_CMD_REQ,
> + UICC_APPL_READ_LINEAR_FIXED,
> + sd->app_id,
> + UICC_SESSION_ID_NOT_USED, /*Session ID*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 3, /*number of subblocks*/
> + /* Subblock 1*/
> + UICC_SB_CLIENT >> 8,
> + UICC_SB_CLIENT & 0xff,
> + 0,
> + 8, /*Sub block length */
> + 0, 0, 0, /* Filler */
> + sd->client_id,
> + /* Subblock 2 */
> + UICC_SB_LINEAR_FIXED >> 8,
> + UICC_SB_LINEAR_FIXED & 0xff,
> + 0, /*Sub block length*/
> + 8, /*Sub block length*/
> + record, /*Record*/
> + 0, /*Record offset (0=beginning)*/
> + rec_length & 0xff, /*Data amount (0=all)*/
> + 0, /*Filler*/
> + /* Subblock 3*/
> + UICC_SB_APPL_PATH >> 8,
> + UICC_SB_APPL_PATH & 0xff,
> + 0,
> + 16, /*Sub block length*/
> + fileid >> 8, /* UICC elementary file ID*/
> + fileid & 0xFF,
> + get_sfi(fileid), /* Elementary file short file id*/
> + 0, /*filler*/
> + df_len, /*DF Path length*/
> + 0, /*Filler*/
> + mf_path >> 8,
> + mf_path & 0xff,
> + df1_path >> 8, /*DF Path*/
> + df1_path & 0xFF,
> + df2_path >> 8, /*DF Path*/
> + df2_path & 0xFF
> + };
> + g_isi_client_send_with_timeout(
> + sd->client, msg, sizeof(msg), SIM_TIMEOUT,
> + isi_read_file_linear_fixed_resp, cbd, g_free);
> + return;
> + }
> +
> +error:
> + DBG("Not implemented (fileid = %04x)", fileid);
> CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
> + g_free(cbd);
> }
>
> static void isi_read_file_cyclic(struct ofono_sim *sim, int fileid,
> @@ -293,13 +1255,123 @@ static void isi_write_file_transparent(struct ofono_sim *sim, int fileid,
> CALLBACK_WITH_FAILURE(cb, data);
> }
>
> +static void write_file_linear_cb(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_write_cb_t cb = cbd->cb;
> + DBG("");
> +
> + if (check_response_status(msg, UICC_APPL_CMD_RESP,
> + UICC_APPL_UPDATE_LINEAR_FIXED))
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> +
> +}
> +
> static void isi_write_file_linear(struct ofono_sim *sim, int fileid,
> int record, int length,
> const unsigned char *value,
> ofono_sim_write_cb_t cb, void *data)
> {
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> +
> + if (g_isi_client_resource(sd->client) == PN_UICC) {
> + int mf_path = 0;
> + int df1_path = 0;
> + int df2_path = 0;
> + unsigned char df_len = 0;
> + size_t i = 0;
> + size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
> + size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
> + uint8_t *fill_data = g_try_malloc0(fill_count);
> +
> + DBG("");
> +
> + if (!fill_data && fill_count > 0) {
> + g_free(fill_data);
> + goto error;
> + }
> + for (i = 0; i < fill_count; i++)
> + fill_data[i] = 0x00;
> +
> + if (!sd->app_id || !sd->client_id || !sd || !sd->client ||
> + !cbd) {
> + DBG("Parameter error");
> + g_free(fill_data);
> + goto error;
> + }
> +
> + if (get_fileid_path(sim, &mf_path, &df1_path,
> + &df2_path, &df_len, fileid)) {
> + uint8_t msg[] = {
> + UICC_APPL_CMD_REQ,
> + UICC_APPL_UPDATE_LINEAR_FIXED,
> + sd->app_id,
> + UICC_SESSION_ID_NOT_USED,
> + 0x00, 0x00, /* fillers */
> + 0x04, /* nro of sub blocks */
> + /* 1st subblock */
> + UICC_SB_CLIENT >> 8,
> + UICC_SB_CLIENT & 0xFF,
> + 0x00, 0x08, /* subblock length */
> + 0x00, 0x00, 0x00, /* fillers */
> + sd->client_id,
> + /* 2nd subblock */
> + UICC_SB_LINEAR_FIXED >> 8,
> + UICC_SB_LINEAR_FIXED & 0xFF,
> + 0x00, 0x08, /* subblock length */
> + record, /* the record in the file*/
> + 0x00, /* record offset (0 == beginning) */
> + 0x00, /* data amount, used only for reading */
> + 0x00, /* filler */
> + /* 3th subblock */
> + UICC_SB_APPL_PATH >> 8,
> + UICC_SB_APPL_PATH & 0xFF,
> + 0x00, 0x10, /* subblock length */
> + fileid >> 8, /* elementary file id */
> + fileid & 0xFF,
> + get_sfi(fileid),
> + 0x00, /* filler */
> + df_len, /* path length */
> + 0x00, /* filler */
> + mf_path >> 8, /* DF Path MF */
> + mf_path & 0xFF,
> + df1_path >> 8, /* DF Path */
> + df1_path & 0xFF,
> + df2_path >> 8, /* DF Path */
> + df2_path & 0xFF,
> + /* 4nd subblock */
> + UICC_SB_FILE_DATA >> 8,
> + UICC_SB_FILE_DATA & 0xFF,
> + sb_file_data_legth >> 8, /* subblock length */
> + sb_file_data_legth & 0xFF,
> + length >> 24, /* data length */
> + length >> 16, /* need to be shifted */
> + length >> 8,
> + length & 0xFF,
> + };
> +
> + struct iovec iov[3] = {
> + { msg, sizeof(msg) },
> + { (uint8_t *)value, length },
> + { fill_data, fill_count },
> + };
> +
> + if (!g_isi_client_vsend_with_timeout(sd->client, iov,
> + 3, SIM_TIMEOUT, write_file_linear_cb,
> + cbd, g_free)) {
> + g_free(fill_data);
> + goto error;
> + }
> +
> + g_free(fill_data);
> + return;
> + }
> + }
> DBG("Fileid %04X not implemented", fileid);
> +error:
> CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> }
>
> static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
> @@ -309,10 +1381,53 @@ static void isi_write_file_cyclic(struct ofono_sim *sim, int fileid,
> DBG("Fileid %04X not implemented", fileid);
> CALLBACK_WITH_FAILURE(cb, data);
> }
> -
> -static void imsi_resp_cb(const GIsiMessage *msg, void *data)
> +static void uicc_read_imsi_resp(const struct ofono_error *error,
> + const unsigned char *data,
> + int len,
> + void *user)
> {
> - struct isi_cb_data *cbd = data;
> + struct isi_cb_data *cbd = user;
> + ofono_sim_imsi_cb_t cb = cbd->cb;
> + /* For coding see TS 24.008 */
> + char imsi[SIM_MAX_IMSI_LENGTH + 1];
> + int i = 1; /*Skip length, the 1st byte*/
> + int j = 0;
> + int octets;
> +
> + if (data == NULL)
> + goto error;
> +
> + octets = data[0];
> +
> + if (octets != 8 || octets > len)
> + goto error;
> +
> + /* Ignore the low-order semi-octet of the first byte */
> + imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
> +
> + for (i++, j++; i - 1 < octets && j < SIM_MAX_IMSI_LENGTH; i++) {
> + char nibble;
> + imsi[j++] = (data[i] & 0x0F) + '0';
> + nibble = (data[i] & 0xF0) >> 4;
> +
> + if (nibble != 0x0F)
> + imsi[j++] = nibble + '0';
> + }
> +
> + imsi[j] = '\0';
> + DBG("IMSI %s", imsi);
> + CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
> + goto out;
> +error:
> + CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
> +out:
> + g_free(cbd);
> + return;
> +}
> +
> +static void imsi_resp_cb(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> ofono_sim_imsi_cb_t cb = cbd->cb;
>
> struct sim_imsi *resp;
> @@ -321,9 +1436,6 @@ static void imsi_resp_cb(const GIsiMessage *msg, void *data)
> char imsi[SIM_MAX_IMSI_LENGTH + 1];
> size_t i, j;
>
> - if (!check_response_status(msg, SIM_IMSI_RESP_READ_IMSI, READ_IMSI))
> - goto error;
> -
> if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &resp, len))
> goto error;
>
> @@ -352,16 +1464,24 @@ static void isi_read_imsi(struct ofono_sim *sim,
> {
> struct sim_data *sd = ofono_sim_get_data(sim);
> struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> + size_t len;
>
> const uint8_t msg[] = {
> SIM_IMSI_REQ_READ_IMSI,
> READ_IMSI
> };
> - size_t len = sizeof(msg);
>
> if (cbd == NULL || sd == NULL)
> goto error;
>
> + if (g_isi_client_resource(sd->client) == PN_UICC) {
> + isi_read_file_transparent(sim, SIM_EFIMSI_FILEID, 0, 9,
> + uicc_read_imsi_resp, cbd);
> + return;
> + }
> + len = sizeof(msg);
> +
> +
> if (g_isi_client_send(sd->client, msg, len, imsi_resp_cb, cbd, g_free))
> return;
>
> @@ -370,6 +1490,976 @@ error:
> g_free(cbd);
> }
>
> +static void uicc_application_activate_resp(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_sim *sim = data;
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + uint8_t *msg_data = (uint8_t *)g_isi_msg_data(msg);
> +
> + if (!check_response_status(msg, UICC_APPLICATION_RESP,
> + UICC_APPL_HOST_ACTIVATE))
> + return;
> +
> + if ((msg_data[2] == UICC_STATUS_OK) ||
> + (msg_data[2] == UICC_STATUS_APPL_ACTIVE)) {
> + if (!sd->uicc_app_started) {
> + sd->app_id = sd->trying_app_id;
> + sd->app_type = sd->trying_app_type;
> + sd->uicc_app_started = TRUE;
> + DBG("UICC application activated");
> + ofono_sim_inserted_notify(sim, TRUE);
> + ofono_sim_register(sim);
> + g_free(sim_application_list_p);
> + }
> + } else {
> + int i = sim_applications_get_next_index(
> + sim_application_list_p, sd->trying_app_id);
> +
> + if (i == NOT_AVAILABLE) {
> + g_free(sim_application_list_p);
> + return;
> + }
> +
> + DBG("Activation Error, trying to activate APP with ID:%d", i);
> + uicc_application_activate_req(sd->client, sim,
> + sim_application_list_p->app_type[i],
> + sim_application_list_p->app_list[i]);
> + return;
> + }
> +
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_CLIENT: {
> + guint8 client = 0;
> + g_isi_sb_iter_get_byte(&iter, &client, 7);
> + DBG("Client id %d", client);
> + sd->client_id = client;
> + break;
> + }
> + case UICC_SB_FCI:
> + DBG("UICC_SB_FCI");
> +
> + if (sd->app_type == UICC_APPL_TYPE_UICC_USIM) {
> + uint16_t length, record_length;
> + uint8_t records, structure;
> + handle_app_uicc_usim(&iter, sd, &length,
> + &record_length, &records,
> + &structure);
> + }
> +
> + break;
> + case UICC_SB_CHV:
> + DBG("UICC_SB_CHV");
> +
> + if (sd->app_type == UICC_APPL_TYPE_ICC_SIM) {
> + uint8_t chv_id = 0, pin_id = 0;
> + (void) g_isi_sb_iter_get_byte(&iter,
> + &chv_id, 4);
> + (void) g_isi_sb_iter_get_byte(&iter,
> + &pin_id, 5);
> + DBG("UICC_APPL_TYPE_UICC_SIM");
> +
> + if (chv_id == 1)
> + sd->pin1_id = pin_id;
> + else if (chv_id == 2)
> + sd->pin2_id = pin_id;
> + }
> +
> + break;
> + default:
> + DBG("Skipping sub-block: %s (%zu bytes)",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)),
> + g_isi_sb_iter_get_len(&iter));
> + break;
> + }
> +
> + (void)g_isi_sb_iter_next(&iter);
> + }
> +}
> +
> +static void uicc_application_activate_req(GIsiClient *client,
> + void *opaque,
> + unsigned char appl_type,
> + unsigned char aid)
> +{
> + const unsigned char msg[] = {
> + UICC_APPLICATION_REQ,
> + UICC_APPL_HOST_ACTIVATE,
> + 2, /* number of subblocks*/
> + /* Subblock 1 */
> + UICC_SB_APPLICATION >> 8,
> + UICC_SB_APPLICATION & 0xff,
> + 0, /*subblock length*/
> + 8, /*subblock length*/
> + 0, /*filler*/
> + 0, /*filler*/
> + appl_type,
> + aid,
> + /* Subblock 2 */
> + UICC_SB_APPL_INFO >> 8,
> + UICC_SB_APPL_INFO & 0xff,
> + 0, /*subblock length*/
> + 8, /*subblock length*/
> + 0, /*filler*/
> + 0, /*filler*/
> + 0, /*filler*/
> + /* whether the application initialization procedure
> + * will follow the activation or not */
> + UICC_APPL_START_UP_INIT_PROC
> + };
> +
> + DBG("Appl type %d, AID %d", appl_type, aid);
> +
> + g_isi_client_send_with_timeout(
> + client, msg, sizeof(msg), SIM_TIMEOUT,
> + uicc_application_activate_resp, opaque, NULL);
> +}
> +
> +static void uicc_application_list_resp(const GIsiMessage *msg, void *data)
> +{
> + struct ofono_sim *sim = data;
> + gboolean everything_ok = TRUE;
> + int index = NOT_AVAILABLE;
> + struct sim_data *sd = ofono_sim_get_data(sim);
> +
> + if (!check_response_status(msg, UICC_APPLICATION_RESP,
> + UICC_APPL_LIST)) {
> + uint8_t status = 0;
> +
> + g_isi_msg_data_get_byte(msg, 2, &status);
> + if (status != UICC_STATUS_FAIL)
> + return;
> + everything_ok = FALSE;
> + }
> +
> + sim_application_list_p = g_try_new0(struct sim_applications, 1);
> +
> + if (everything_ok) {
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(
> + g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_APPL_DATA_OBJECT: {
> + guint8 appl_id = -1;
> + guint8 appl_type = -1;
> + guint8 status = -1;
> + gboolean ret;
> + ret = g_isi_sb_iter_get_byte(
> + &iter, &appl_type, 6);
> + ret = g_isi_sb_iter_get_byte(
> + &iter, &appl_id, 7);
> + (void) g_isi_sb_iter_get_byte(
> + &iter, &status, 8);
> + DBG("Appl type=%d, Appl id=%d, Appl status=%d",
> + appl_type, appl_id, status);
> +
> + sim_application_list_p->app_list[appl_id] =
> + appl_id;
> + sim_application_list_p->app_type[appl_id] =
> + appl_type;
> + break;
> + }
> + default:
> + DBG("Skipping sub-block: %s (%zu bytes)",
> + uicc_subblock_name(
> + g_isi_sb_iter_get_id(&iter)),
> + g_isi_sb_iter_get_len(&iter));
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> + }
> +
> + if (!sd->uicc_app_started) {
> + index = sim_applications_get_next_index(sim_application_list_p,
> + NOT_ACTIVATED);
> +
> + if (index != NOT_AVAILABLE) {
> + DBG("Activating APP index:%d", index);
> + sd->trying_app_id =
> + sim_application_list_p->app_list[index];
> + sd->trying_app_type =
> + sim_application_list_p->app_type[index];
> + DBG("Activating APP ID: %d APP type: %d",
> + sd->trying_app_id, sd->trying_app_type);
> + uicc_application_activate_req(sd->client, sim,
> + sim_application_list_p->app_type[index],
> + sim_application_list_p->app_list[index]);
> + } else
> + g_free(sim_application_list_p);
> + }
> +}
> +
> +static void uicc_application_list_req(GIsiClient *client,
> + void *opaque)
> +{
> + const unsigned char msg[] = {
> + UICC_APPLICATION_REQ,
> + UICC_APPL_LIST,
> + 0 /* number of subblocks*/
> + };
> + DBG("");
> +
> + g_isi_client_send_with_timeout(
> + client, msg, sizeof(msg), SIM_TIMEOUT,
> + uicc_application_list_resp, opaque, NULL);
> +}
> +
> +static void uicc_pin_enter_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> + struct ofono_sim_local *local_sim =
> + (struct ofono_sim_local *) cbd->user;
> + struct ofono_error error;
> + GIsiSubBlockIter iter;
> + struct sim_data *sd =
> + ofono_sim_get_data((struct ofono_sim *) local_sim);
> + uint8_t status = 0, sbcount = 0;
> +
> + if (msg == NULL)
> + goto error;
Looks reasonable...
> + g_isi_msg_data_get_byte(msg, 2, &status);
> + if (status == UICC_STATUS_OK) {
> + sd->passwd_required = FALSE;
> + error.type = OFONO_ERROR_TYPE_NO_ERROR;
> + error.error = 0;
> + goto out;
> + }
> +
> +error:
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
Huh? You ended up here because msg == NULL!
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_STATUS_WORD: {
> + uint16_t status;
> + g_isi_sb_iter_get_word(&iter, &status, 6);
> + DBG("APDU status word = %04X", status);
> +
> + switch (status) {
> + case 0x6983:
> + case 0x9840:
Why aren't these in some PN_UICC related enum?
> + DBG("Authentication method blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + break;
> + default:
> +
> + if ((status & 0xfff0) == 0x63c0)
> + DBG("Attempts left %d", status & 0xf);
> +
> + break;
> + }
> +
> + break;
> + }
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +
> + error.type = OFONO_ERROR_TYPE_FAILURE;
> + error.error = 1;
> +out:
> + cb(&error, cbd->data);
Could you use the CALLBACK_WITH_* macros here instead?
> +}
> +
> +static void uicc_pin_enter(struct ofono_sim *sim, const char *passwd,
> + ofono_sim_lock_unlock_cb_t cb, void *data)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> + sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
> + DBG("PIN=%s PINID=%02x", passwd, sd->current_pin_id);
> +
> + if (cbd && sd) {
> + unsigned char pinlen = strlen(passwd);
> + unsigned char msg[] = {
> + UICC_PIN_REQ,
> + UICC_PIN_VERIFY,
> + sd->app_id,
> + 0, /* Filler */
> + 0, /* Filler */
> + 0, /* Filler */
> + 1, /* number of subblocks */
> + /* Subblock 1 */
> + UICC_SB_PIN >> 8,
> + UICC_SB_PIN & 0xff,
> + 0,
> + 16, /* Max length */
> + sd->current_pin_id, /* PIN id */
> + UICC_PIN_OLD, /* PIN qualifier */
> + pinlen, /* PIN length */
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0
> + };
> +
> + if ((pinlen < 4) || (pinlen > 8))
> + goto error;
> +
> + memmove(&msg[14], passwd, pinlen);
We have typically used struct iovec and the vsend() API for these
types of messages.
> + g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
> + SIM_TIMEOUT, uicc_pin_enter_resp, cbd,
> + g_free);
> + return;
> + }
> +
> +error:
> + CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> +}
> +
> +enum ofono_sim_password_type passwd_type_for_query =
> + OFONO_SIM_PASSWORD_SIM_PIN;
Just put OFONO_SIM_PASSWORD_SIM_PIN directly in those two places where
you end up using this.
> +static void uicc_pin_prompt_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_passwd_cb_t cb = cbd->cb;
> + struct ofono_sim_local *local_sim =
> + (struct ofono_sim_local *) cbd->user;
> + struct sim_data *sd =
> + ofono_sim_get_data((struct ofono_sim *)local_sim);
> +
> + unsigned char lock_type = -1;
> + GIsiSubBlockIter iter;
> + uint8_t status = UICC_STATUS_UNKNOWN;
> + uint8_t pin_attempts = -1;
> + uint8_t puk_attempts = -1;
> +
> + if (!check_response_status(msg, UICC_PIN_RESP,
> + UICC_PIN_PROMPT_VERIFY) && !check_response_status(msg,
> + UICC_PIN_RESP, UICC_PIN_INFO))
> + goto error;
> +
> + if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
> + sd->pin_state_received = TRUE;
> + g_isi_msg_data_get_byte(msg, 2, &status);
> + } else if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_INFO)) {
> + uint8_t sbcount = 0;
> +
> + sd->pin_state_received = TRUE;
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(
> + &iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_PIN_INFO:
> + g_isi_sb_iter_get_byte(&iter, &status, 4);
> + g_isi_sb_iter_get_byte(&iter,
> + &pin_attempts, 5);
> + g_isi_sb_iter_get_byte(&iter,
> + &puk_attempts, 6);
> + DBG("Status=%s, PIN attempts=%d, \
> + PUK attempts=%d",
> + uicc_status_name(status),
> + pin_attempts, puk_attempts);
> + break;
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> + }
> +
> + if ((status == UICC_STATUS_OK) ||
> + (status == UICC_STATUS_PIN_ENABLED)) {
> + /* PIN query on, indication should tell
> + * if it is verified or not
> + */
> + if (pin_attempts == 0) {
> + DBG("PIN blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + } else {
> + DBG("PIN query enabled");
> + update_locked_pin(local_sim,
> + UICC_PIN_VERIFY_NEEDED,
> + sd->current_pin_id);
> + }
> +
> + lock_type = local_sim->pin_type;
> + } else if (status == UICC_STATUS_PIN_DISABLED) {
> + if (pin_attempts == 0) {
> + DBG("PIN blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + lock_type = local_sim->pin_type;
> + } else {
> + DBG("PIN query disabled");
> + local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] =
> + FALSE;
> + local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] =
> + FALSE;
> + lock_type = OFONO_SIM_PASSWORD_NONE;
> + }
> + }
> +
> + if (check_response_status(msg, UICC_PIN_RESP, UICC_PIN_PROMPT_VERIFY)) {
> + uicc_pin_prompt(cbd->user,
> + passwd_type_for_query,
> + cb,
> + cbd->data,
> + UICC_PIN_INFO);
> + }
> +
> + CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
> + return;
> +error:
> + DBG("PIN prompt verify failed");
> + CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
> +}
> +
> +static void uicc_pin_prompt(struct ofono_sim *sim,
> + enum ofono_sim_password_type passwd_type,
> + ofono_sim_passwd_cb_t cb,
> + void *data,
> + uint8_t service)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> + int8_t index;
> + sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
> + DBG("PINID = %02x", sd->current_pin_id);
> +
> + if ((cbd) && (sd) && (sd->current_pin_id)) {
Check for NULL here, and for zero pin_id, and return with error.
> + unsigned char msg[] = {
> + UICC_PIN_REQ,
> + service,
> + sd->app_id,
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 1, /*number of subblocks*/
> + /* Subblock 1 */
> + UICC_SB_PIN_REF >> 8,
> + UICC_SB_PIN_REF & 0xff,
> + 0, /*Sub block length.*/
> + 8,
> + sd->current_pin_id, /*PIN ID*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0 /*Filler*/
> + };
> + g_isi_client_send_with_timeout(sd->client, msg, sizeof(msg),
> + SIM_TIMEOUT, uicc_pin_prompt_resp, cbd,
> + g_free);
> + } else {
> + DBG("PIN info query failed");
> + CALLBACK_WITH_FAILURE(cb, -1, data);
> + g_free(cbd);
> + }
> +}
> +
> +static void uicc_passwd_state_query(struct ofono_sim *sim,
> + ofono_sim_passwd_cb_t cb,
> + void *data)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct ofono_sim_local *local_sim = (struct ofono_sim_local *)sim;
> +
> + if (sd->pin_state_received) {
> + int lock_type = OFONO_SIM_PASSWORD_NONE;
> +
> + if (sd->passwd_required) {
> + /* These should be in priority order, highest last */
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PIN] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_SIM_PIN;
> +
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PIN2] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_SIM_PIN2;
> +
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_PHNET_PIN] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_PHNET_PIN;
> +
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PUK] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_SIM_PUK;
> +
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_SIM_PUK2] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_SIM_PUK2;
> +
> + if (local_sim->locked_pins[
> + OFONO_SIM_PASSWORD_PHNET_PUK] == TRUE)
> + lock_type = OFONO_SIM_PASSWORD_PHNET_PUK;
> + }
> +
> + DBG("UICC lock type=%d", lock_type);
> + CALLBACK_WITH_SUCCESS(cb, lock_type, data);
> + } else {
> + if (sd->uicc_app_started) {
> + /* No indication received but UICC app is
> + * started, let's query the state
> + */
> + DBG("Querying PIN info");
> + uicc_pin_prompt(sim, passwd_type_for_query,
> + cb, data, UICC_PIN_PROMPT_VERIFY);
> + return;
> + }
> +
> + DBG("No UICC_PIN_IND received");
> + CALLBACK_WITH_FAILURE(cb, -1, data);
> + }
> +}
> +
> +static void uicc_pin_enable_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> + struct ofono_sim_local *local_sim =
> + (struct ofono_sim_local *) cbd->user;
> + struct sim_data *sd =
> + ofono_sim_get_data((struct ofono_sim *) local_sim);
> +
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> +
> + if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_DISABLE) &&
> + !check_response_status(msg, UICC_PIN_RESP,
> + UICC_PIN_ENABLE))
> + goto error;
> +
> + DBG("PIN lock/unlock succeeded");
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
> +
> +error:
> + g_isi_msg_data_get_byte(msg, 5, &sbcount);
> + g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, sbcount);
> +
> + while (g_isi_sb_iter_is_valid(&iter)) {
> + DBG("Sub-block %s",
> + uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
> +
> + switch (g_isi_sb_iter_get_id(&iter)) {
> + case UICC_SB_STATUS_WORD: {
> + uint16_t status;
> + g_isi_sb_iter_get_word(&iter, &status, 6);
> + DBG("APDU status word = %04X", status);
> +
> + switch (status) {
> + case 0x6983:
> + case 0x9840:
> + DBG("Authentication method blocked");
> + update_locked_pin(local_sim,
> + UICC_PIN_UNBLOCK_NEEDED,
> + sd->current_pin_id);
> + break;
> + default:
> +
> + if ((status & 0xfff0) == 0x63c0)
> + DBG("Attempts left %d", status & 0xf);
> +
> + break;
> + }
> + }
> + default:
> + break;
> + }
> +
> + g_isi_sb_iter_next(&iter);
> + }
> +
> + DBG("PIN lock/unlock failed");
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> +}
> +
> +static void uicc_pin_enable(struct ofono_sim *sim,
> + enum ofono_sim_password_type passwd_type,
> + int enable, const char *passwd,
> + ofono_sim_lock_unlock_cb_t cb, void *data)
> +{
> + struct sim_data *sd = ofono_sim_get_data(sim);
> + struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
> + int8_t index;
> + unsigned char service = 0;
> + sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
> +
> + DBG("Lock=%d, PIN code=%s, PIN ID =%d",
> + enable, passwd, sd->current_pin_id);
> + if (enable) {
> + DBG("Enabling PIN");
> + service = UICC_PIN_ENABLE;
> + } else {
> + DBG("Disabling PIN");
> + service = UICC_PIN_DISABLE;
> + }
> + if ((cbd) && (sd) && (sd->current_pin_id)) {
> +
> + unsigned char pinlen = strlen(passwd);
> +
> + unsigned char msg[] = {
> + UICC_PIN_REQ,
> + service,
> + sd->app_id,
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 0, /*Filler*/
> + 1, /*number of subblocks*/
> + /* Subblock 1 */
> + UICC_SB_PIN >> 8,
> + UICC_SB_PIN & 0xff,
> + 0,
> + 16, /*Max length*/
> + sd->current_pin_id, /* PIN id */
> + UICC_PIN_OLD, /* PIN qualifier */
> + pinlen, /* PIN length */
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0
> + };
> +
> + if ((pinlen < 4) || (pinlen > 8))
> + goto error;
> + memmove(&msg[14], passwd, pinlen);
> + g_isi_client_send_with_timeout(
> + sd->client, msg, sizeof(msg), SIM_TIMEOUT,
> + uicc_pin_enable_resp, cbd, g_free);
> + return;
> + }
> +
> +error:
> + DBG("Error");
> + CALLBACK_WITH_FAILURE(cb, data);
> + g_free(cbd);
> + return;
> +}
> +
> +static void uicc_pin_change_resp(const GIsiMessage *msg, void *data)
> +{
> + struct isi_cb_data *cbd = data;
> + ofono_sim_lock_unlock_cb_t cb = cbd->cb;
> + struct ofono_sim_local *local_sim =
> + (struct ofono_sim_local *) cbd->user;
> + struct sim_data *sd =
> + ofono_sim_get_data((struct ofono_sim *) local_sim);
> +
> + GIsiSubBlockIter iter;
> + uint8_t sbcount = 0;
> +
> + if (!check_response_status(msg, UICC_PIN_RESP, UICC_PIN_CHANGE))
> + goto error;
> +
> + DBG("PIN change succeeded");
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
> +
> +error:
Same as above, this can't be right that you end up decoding the
message when there is a response reporting failure?
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 09/18] isimodem: clip colp clir colr wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (7 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 08/18] isimodem: UICC sim support for wgmodem2.5 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-18 8:15 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
` (8 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 23346 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-settings.c | 697 +++++++++++++++++++++++++++++++++++++-
drivers/isimodem/call.h | 9 +
drivers/isimodem/debug.c | 4 +
drivers/isimodem/ss.h | 22 ++
4 files changed, 714 insertions(+), 18 deletions(-)
diff --git a/drivers/isimodem/call-settings.c b/drivers/isimodem/call-settings.c
index 89270e9..7a6bedf 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
@@ -43,10 +44,15 @@
#include "ss.h"
#include "debug.h"
+#define CLIP_ETC
+
struct settings_data {
GIsiClient *client;
};
+#define content_size 40
+static char content[content_size] = {0};
+
static void update_status_mask(unsigned int *mask, int bsc)
{
switch (bsc) {
@@ -88,7 +94,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 +109,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 +194,611 @@ 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 int set_clir_status(const char *value)
+{
+ DBG("Setting CLIR status to %s", value);
+ strncpy(content, value, content_size);
+ content[content_size-1] = 0;
+ return EXIT_SUCCESS;
+}
+
+static int get_clir_status(void)
+{
+ DBG("Getting CLIR status %s", content);
+
+ if (!strcmp(content, "OFONO_CLIR_OPTION_INVOCATION"))
+ return OFONO_CLIR_OPTION_INVOCATION;
+
+ if (!strcmp(content, "OFONO_CLIR_OPTION_SUPPRESSION"))
+ return OFONO_CLIR_OPTION_SUPPRESSION;
+
+ return OFONO_CLIR_OPTION_DEFAULT;
+}
+
+static void clir_set_cb(const GIsiMessage *msg, void *data)
+{
+ GIsiSubBlockIter iter, iter_info;
+ struct isi_cb_data *cbd = data;
+ ofono_call_settings_set_cb_t cb = cbd->cb;
+ 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;
+ 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)) {
+ 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;
+ }
+
+ DBG("SS_STATUS_RESULT=%d, CLIR_OPTION=%d",
+ ss_status, clir_option);
+ }
+
+ if (network != CLIR_STATUS_NOT_PROVISIONED) {
+ int result;
+ DBG("CLIR set successfully.");
+ result = set_clir_status(
+ "OFONO_CLIR_OPTION_INVOCATION");
+
+ if (result == EXIT_FAILURE)
+ goto error;
+ } 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;
+ }
+ }
- if (!decode_gsm_bsc_info(&iter, &mask))
+ 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):
+ result = set_clir_status("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) */
+ result = set_clir_status("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;
+ uint8_t service;
+ gint override = OFONO_CLIR_OPTION_DEFAULT;
+ gint network = CLIR_STATUS_UNKNOWN;
+
+
+ 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();
+ 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;
- CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+ 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 +851,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,6 +933,7 @@ 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;
@@ -302,11 +963,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] 38+ messages in thread* Re: [PATCH 09/18] isimodem: clip colp clir colr wgmodem2.5
2011-02-15 12:31 ` [PATCH 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
@ 2011-02-18 8:15 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-18 8:15 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 19043 bytes --]
Hi Andreas,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/call-settings.c | 697 +++++++++++++++++++++++++++++++++++++-
> drivers/isimodem/call.h | 9 +
> drivers/isimodem/debug.c | 4 +
> drivers/isimodem/ss.h | 22 ++
> 4 files changed, 714 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/isimodem/call-settings.c b/drivers/isimodem/call-settings.c
> index 89270e9..7a6bedf 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
> @@ -43,10 +44,15 @@
> #include "ss.h"
> #include "debug.h"
>
> +#define CLIP_ETC
> +
I don't see this used anywhere in the code.
> struct settings_data {
> GIsiClient *client;
> };
>
> +#define content_size 40
> +static char content[content_size] = {0};
> +
(snip)
> +static int set_clir_status(const char *value)
> +{
> + DBG("Setting CLIR status to %s", value);
> + strncpy(content, value, content_size);
> + content[content_size-1] = 0;
> + return EXIT_SUCCESS;
> +}
> +
> +static int get_clir_status(void)
> +{
> + DBG("Getting CLIR status %s", content);
> +
> + if (!strcmp(content, "OFONO_CLIR_OPTION_INVOCATION"))
> + return OFONO_CLIR_OPTION_INVOCATION;
> +
> + if (!strcmp(content, "OFONO_CLIR_OPTION_SUPPRESSION"))
> + return OFONO_CLIR_OPTION_SUPPRESSION;
> +
> + return OFONO_CLIR_OPTION_DEFAULT;
> +}
I don't understand this part. Why is 'content' a static buffer, and
why is strncpy() used? All I see are const strings copied there.
Also, if the getter anyway returns an int, why not store an int there
in the first place? Could it also be part of the call-settings driver
data?
> +static void clir_set_cb(const GIsiMessage *msg, void *data)
> +{
> + GIsiSubBlockIter iter, iter_info;
> + struct isi_cb_data *cbd = data;
> + ofono_call_settings_set_cb_t cb = cbd->cb;
> + 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;
> + 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)) {
> + 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;
> + }
> +
> + DBG("SS_STATUS_RESULT=%d, CLIR_OPTION=%d",
> + ss_status, clir_option);
> + }
> +
> + if (network != CLIR_STATUS_NOT_PROVISIONED) {
> + int result;
> + DBG("CLIR set successfully.");
> + result = set_clir_status(
> + "OFONO_CLIR_OPTION_INVOCATION");
> +
> + if (result == EXIT_FAILURE)
> + goto error;
> + } 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;
> + }
> + }
>
> - if (!decode_gsm_bsc_info(&iter, &mask))
> + DBG("override=%d, network=%d\n", override, network);
> + CALLBACK_WITH_SUCCESS(cb, cbd->data);
> + return;
> +error:
> + CALLBACK_WITH_FAILURE(cb, cbd->data);
> +}
This function is really hard to follow. I would consider breaking it
up so that each sub-block decoder is a separate static function of its
own.
> +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):
> + result = set_clir_status("OFONO_CLIR_OPTION_DEFAULT");
> + break;
Indentation is broken here.
> + /* 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) */
> + result = set_clir_status("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;
> + uint8_t service;
> + gint override = OFONO_CLIR_OPTION_DEFAULT;
> + gint network = CLIR_STATUS_UNKNOWN;
> +
> +
> + 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;
Indentation is broken here. Why is the break outside the brackets anyway?
> + 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();
> + 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);
> +}
Same as above; this function needs some refactoring to split the
decoding up into several functions.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 10/18] isimodem: wgmodem2.5 added to voicecall
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (8 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 09/18] isimodem: clip colp clir colr wgmodem2.5 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 11/18] isimodem: gprs-context updates wgmodem2.5 Andreas Westin
` (7 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 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] 38+ messages in thread* [PATCH 11/18] isimodem: gprs-context updates wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (9 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 10/18] isimodem: wgmodem2.5 added to voicecall Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-18 14:17 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 12/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
` (6 subsequent siblings)
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 4262 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/gprs-context.c | 95 +++++++++++++++++++++++++-------------
1 files changed, 62 insertions(+), 33 deletions(-)
diff --git a/drivers/isimodem/gprs-context.c b/drivers/isimodem/gprs-context.c
index 6d579d8..f458fcc 100644
--- a/drivers/isimodem/gprs-context.c
+++ b/drivers/isimodem/gprs-context.c
@@ -347,32 +347,52 @@ static void send_context_authenticate(GIsiClient *client, void *opaque)
struct context_data *cd = opaque;
size_t username_len = strlen(cd->username);
size_t password_len = strlen(cd->password);
+ size_t sb_user_info_len = (3 + username_len + 3) & ~3;
+ size_t fill_sb_user_info_count =
+ sb_user_info_len - (3 + username_len);
+ uint8_t *fill_sb_user_info_data =
+ g_try_malloc0(fill_sb_user_info_count);
+ size_t sb_password_info_len = (3 + password_len + 3) & ~3;
+ size_t fill_sb_password_info_count =
+ sb_user_info_len - (3 + password_len);
+ uint8_t *fill_sb_password_info_data =
+ g_try_malloc0(fill_sb_password_info_count);
const unsigned char top[] = {
GPDS_CONTEXT_AUTH_REQ,
cd->handle,
2, /* sub blocks */
GPDS_USER_NAME_INFO,
- 3 + username_len + 3,
+ sb_user_info_len,
username_len,
/* Username goes here */
};
const unsigned char bottom[] = {
GPDS_PASSWORD_INFO,
- 3 + password_len + 3,
+ sb_password_info_len,
password_len,
/* Password goes here */
};
- const struct iovec iov[4] = {
- { (uint8_t *) top, sizeof(top) },
+ const struct iovec iov[6] = {
+ { (uint8_t *)top, sizeof(top) },
{ cd->username, username_len },
- { (uint8_t *) bottom, sizeof(bottom) },
+ { fill_sb_user_info_data, fill_sb_user_info_count },
+ { (uint8_t *)bottom, sizeof(bottom) },
{ cd->password, password_len },
+ { fill_sb_password_info_data, fill_sb_password_info_count},
};
- if (!g_isi_client_vsend(client, iov, 4, context_auth_cb, cd, NULL))
+ if (fill_sb_user_info_data == NULL
+ && fill_sb_user_info_count > 0)
+ gprs_up_fail(cd);
+
+ if (fill_sb_password_info_data == NULL
+ && fill_sb_password_info_count > 0)
+ gprs_up_fail(cd);
+
+ if (!g_isi_client_vsend(client, iov, 6, context_auth_cb, cd, NULL))
gprs_up_fail(cd);
}
@@ -393,34 +413,43 @@ static void link_conf_cb(const GIsiMessage *msg, void *opaque)
{
struct context_data *cd = opaque;
size_t apn_len = strlen(cd->apn);
+ size_t sb_apn_info_len = (3 + apn_len + 3) & ~3;
+ size_t fill_count = sb_apn_info_len - (3 + apn_len);
+ uint8_t *fill_data = g_try_malloc0(fill_count);
+
+ if (fill_data == NULL && fill_count > 0)
+ return gprs_up_fail(cd);
+
+ if (check_resp(msg, GPDS_LL_CONFIGURE_RESP, 2, cd, gprs_up_fail)) {
+
+ const unsigned char msg[] = {
+ GPDS_CONTEXT_CONFIGURE_REQ,
+ cd->handle, /* context ID */
+ cd->type, /* PDP type */
+ GPDS_CONT_TYPE_NORMAL,
+ cd->handle, /* primary context ID */
+ 0x00, /* filler */
+ 2, /* sub blocks */
+ GPDS_DNS_ADDRESS_REQ_INFO,
+ 4, /* subblock length */
+ 0, 0, /* padding */
+ GPDS_APN_INFO,
+ sb_apn_info_len,
+ apn_len,
+ };
+
+ const struct iovec iov[3] = {
+ { (uint8_t *)msg, sizeof(msg) },
+ { cd->apn, apn_len },
+ { fill_data, fill_count}
+ };
+
+ if (!g_isi_client_vsend_with_timeout(cd->client, iov, 3,
+ GPDS_TIMEOUT, context_conf_cb, cd, NULL))
+ return gprs_up_fail(cd);
+ } else
+ return gprs_up_fail(cd);
- const unsigned char req[] = {
- GPDS_CONTEXT_CONFIGURE_REQ,
- cd->handle, /* context ID */
- cd->type, /* PDP type */
- GPDS_CONT_TYPE_NORMAL,
- cd->handle, /* primary context ID */
- 0x00, /* filler */
- 2, /* sub blocks */
- GPDS_DNS_ADDRESS_REQ_INFO,
- 4, /* subblock length */
- 0, 0, /* padding */
- GPDS_APN_INFO,
- 3 + apn_len + 3,
- apn_len,
- };
-
- const struct iovec iov[2] = {
- { (uint8_t *) req, sizeof(req) },
- { cd->apn, apn_len },
- };
-
- if (!check_resp(msg, GPDS_LL_CONFIGURE_RESP, 2, cd, gprs_up_fail))
- return;
-
- if (!g_isi_client_vsend(cd->client, iov, 2,
- context_conf_cb, cd, NULL))
- gprs_up_fail(cd);
}
static void create_context_cb(const GIsiMessage *msg, void *opaque)
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH 11/18] isimodem: gprs-context updates wgmodem2.5
2011-02-15 12:31 ` [PATCH 11/18] isimodem: gprs-context updates wgmodem2.5 Andreas Westin
@ 2011-02-18 14:17 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-18 14:17 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1664 bytes --]
Hi,
2011/2/15 Andreas Westin <andreas.westin@stericsson.com>:
> From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
>
> ---
> drivers/isimodem/gprs-context.c | 95 +++++++++++++++++++++++++-------------
> 1 files changed, 62 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/isimodem/gprs-context.c b/drivers/isimodem/gprs-context.c
> index 6d579d8..f458fcc 100644
> --- a/drivers/isimodem/gprs-context.c
> +++ b/drivers/isimodem/gprs-context.c
> @@ -347,32 +347,52 @@ static void send_context_authenticate(GIsiClient *client, void *opaque)
> struct context_data *cd = opaque;
> size_t username_len = strlen(cd->username);
> size_t password_len = strlen(cd->password);
> + size_t sb_user_info_len = (3 + username_len + 3) & ~3;
> + size_t fill_sb_user_info_count =
> + sb_user_info_len - (3 + username_len);
> + uint8_t *fill_sb_user_info_data =
> + g_try_malloc0(fill_sb_user_info_count);
> + size_t sb_password_info_len = (3 + password_len + 3) & ~3;
> + size_t fill_sb_password_info_count =
> + sb_user_info_len - (3 + password_len);
This should be sb_password_info_len, no?
> + uint8_t *fill_sb_password_info_data =
> + g_try_malloc0(fill_sb_password_info_count);
There's no reason to allocate the padding from heap. (Especially if
they're never freed.)
I applied this patch, but fixed the above issues afterwards. Please
check that it's still doing the right thing.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 12/18] isimodem: wgmodem2.5 support in USSD
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (10 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 11/18] isimodem: gprs-context updates wgmodem2.5 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 13/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
` (5 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2158 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..abc6e09 100644
--- a/drivers/isimodem/ussd.c
+++ b/drivers/isimodem/ussd.c
@@ -166,7 +166,11 @@ 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};
+ GIsiModem *modem;
+ uint8_t iov_size = 2;
+
+ uint8_t msg[] = {
SS_GSM_USSD_SEND_REQ,
ud->mt_session
? SS_GSM_USSD_MT_REPLY
@@ -178,15 +182,34 @@ 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,
+ modem = g_isi_client_modem(ud->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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;
@@ -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] 38+ messages in thread* [PATCH 13/18] isimodem: SS_GSM_BARRING_INFO added
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (11 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 12/18] isimodem: wgmodem2.5 support in USSD Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 14/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
` (4 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 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] 38+ messages in thread* [PATCH 14/18] isimodem: wgmodem2.5 added to call-forwarding
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (12 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 13/18] isimodem: SS_GSM_BARRING_INFO added Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 15/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
` (3 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2963 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-forwarding.c | 31 +++++++++++++++++++++++++++----
1 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/isimodem/call-forwarding.c b/drivers/isimodem/call-forwarding.c
index 89a03dc..74645c3 100644
--- a/drivers/isimodem/call-forwarding.c
+++ b/drivers/isimodem/call-forwarding.c
@@ -212,6 +212,7 @@ static void isi_registration(struct ofono_call_forwarding *cf, int type,
int ss_code;
int num_filler;
char *ucs2 = NULL;
+ GIsiModem *modem;
unsigned char msg[100] = {
SS_SERVICE_REQ,
@@ -230,11 +231,17 @@ 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);
+ modem = g_isi_client_modem(fd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0)
+ msg[10] = SS_UNDEFINED_TIME;
+
ss_code = forw_type_to_isi_code(type);
if (ss_code < 0)
goto error;
@@ -248,6 +255,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,10 +341,12 @@ 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;
+ GIsiModem *modem;
struct ofono_call_forwarding_condition list = {
.status = 0,
@@ -366,8 +379,17 @@ 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;
+ modem = g_isi_client_modem(fd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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;
@@ -447,6 +469,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] 38+ messages in thread* [PATCH 15/18] isimodem: wgmodem2.5 added to ssn
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (13 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 14/18] isimodem: wgmodem2.5 added to call-forwarding Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-15 12:31 ` [PATCH 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
` (2 subsequent siblings)
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 12166 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/call-forwarding.c | 1 -
drivers/isimodem/ssn.c | 382 +++++++++++++++++++++++++++++++++++-
2 files changed, 377 insertions(+), 6 deletions(-)
diff --git a/drivers/isimodem/call-forwarding.c b/drivers/isimodem/call-forwarding.c
index 74645c3..1c9a072 100644
--- a/drivers/isimodem/call-forwarding.c
+++ b/drivers/isimodem/call-forwarding.c
@@ -469,7 +469,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..9f6ceff 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,381 @@
#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"
+#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;
};
+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_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;
+
+ DBG("PN_SSN (v%03d.%03d) reachable.", g_isi_msg_version_major(msg),
+ g_isi_msg_version_minor(msg));
+
+ g_idle_add(isi_ssn_register, ssn);
+}
+
static int isi_ssn_probe(struct ofono_ssn *ssn, unsigned int vendor,
- void *user)
+ void *user)
{
GIsiModem *modem = user;
struct ssn_data *sd;
@@ -54,7 +416,17 @@ 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);
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+
+ sd->client = g_isi_client_create(modem, PN_MODEM_CALL);
+
+ if (sd->client)
+ g_isi_client_verify(sd->client, ssn_reachable_cb, ssn,
+ NULL);
+ } else
+ sd->client = g_isi_client_create(modem, PN_SS);
+
if (sd->client == NULL) {
g_free(sd);
return -ENOMEM;
@@ -79,9 +451,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] 38+ messages in thread* [PATCH 16/18] isimodem: sms updated with wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (14 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 15/18] isimodem: wgmodem2.5 added to ssn Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-16 14:22 ` Aki Niemi
2011-02-15 12:31 ` [PATCH 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
2011-02-15 12:31 ` [PATCH 18/18] isimodem: initial support for UICC phonebook Andreas Westin
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 39096 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/debug.c | 56 +++
drivers/isimodem/debug.h | 1 +
drivers/isimodem/sms.c | 972 +++++++++++++++++++++++++++++++++++++++-------
drivers/isimodem/sms.h | 34 ++
4 files changed, 927 insertions(+), 136 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.c b/drivers/isimodem/sms.c
index 957b342..5ec1226 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,51 @@ struct sms_common {
uint8_t *data;
};
+const unsigned char SMS_STATUS_REPORT = 0x02;
+
struct sms_data {
GIsiClient *client;
GIsiClient *sim;
- struct sim_efsmsp params;
+ 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 +194,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 +210,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 +232,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 +352,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 +388,85 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
+static gboolean sca_query_uicc(struct sms_data *sd, struct isi_cb_data *cbd)
+{
+ int8_t app_id = get_app_id();
+ uint8_t client_id = get_client_id();
+ int app_type = get_app_type();
+ 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 +476,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 +503,102 @@ 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)
+{
+ int8_t app_id = get_app_id();
+ int8_t app_type = get_app_type();
+ int8_t client_id = get_client_id();
+ 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 +606,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 +641,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;
@@ -348,84 +705,253 @@ 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);
+ GIsiModem *modem;
- 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;
+ modem = g_isi_client_modem(sd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+
+ 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;
+ GIsiModem *modem;
+ int cause_pos = 0;
+
+ if (cbd == NULL)
return;
+ sd = ofono_sms_get_data(cbd->user);
+
+ if (sd == NULL)
+ goto error;
+
+ modem = g_isi_client_modem(sd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0)
+ 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 +982,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 +992,46 @@ 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;
+ GIsiModem *modem;
- 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);
+ modem = g_isi_client_modem(sd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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 +1129,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 +1140,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,43 +1244,85 @@ 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)
{
struct ofono_sms *sms = data;
struct sms_data *sd = ofono_sms_get_data(sms);
+ GIsiModem *modem;
if (g_isi_msg_error(msg) < 0) {
DBG("unable to find SMS resource");
return;
}
+ if (sd == NULL)
+ return;
+
ISI_VERSION_DBG(msg);
- g_isi_client_verify(sd->sim, sim_reachable_cb, sms, NULL);
+ modem = g_isi_client_modem(sd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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, uicc_reachable_cb, sms, NULL);
}
static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
@@ -664,28 +1334,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;
}
@@ -693,29 +1379,43 @@ nomem:
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);
+ GIsiModem *modem;
if (sd == NULL)
return;
+ modem = g_isi_client_modem(sd->client);
+ 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 (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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);
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] 38+ messages in thread* Re: [PATCH 16/18] isimodem: sms updated with wgmodem2.5
2011-02-15 12:31 ` [PATCH 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
@ 2011-02-16 14:22 ` Aki Niemi
2011-02-16 14:47 ` Andreas WESTIN
0 siblings, 1 reply; 38+ messages in thread
From: Aki Niemi @ 2011-02-16 14:22 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3705 bytes --]
Hi,
2011/2/15 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.c | 972 +++++++++++++++++++++++++++++++++++++++-------
> drivers/isimodem/sms.h | 34 ++
> 4 files changed, 927 insertions(+), 136 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>";
> +}
> +
This UICC stuff seems to be leftovers form patch 8/18.
(snip)
> @@ -664,28 +1334,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);
> +
After this, the driver will no longer work with N900 or the isimodem plugin.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH 16/18] isimodem: sms updated with wgmodem2.5
2011-02-16 14:22 ` Aki Niemi
@ 2011-02-16 14:47 ` Andreas WESTIN
2011-02-17 10:30 ` Aki Niemi
0 siblings, 1 reply; 38+ messages in thread
From: Andreas WESTIN @ 2011-02-16 14:47 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3753 bytes --]
Hi,
On 2011-02-16 15:22, Aki Niemi wrote:
> Hi,
>
> 2011/2/15 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.c | 972 +++++++++++++++++++++++++++++++++++++++-------
>> drivers/isimodem/sms.h | 34 ++
>> 4 files changed, 927 insertions(+), 136 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>";
>> +}
>> +
>
> This UICC stuff seems to be leftovers form patch 8/18.
Well they are related to SMS, debug prints. But yes they are also UICC.
Do you want them in patch 8 ?
>
>> @@ -664,28 +1334,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);
>> +
>
> After this, the driver will no longer work with N900 or the isimodem plugin.
PN_SIM client is created in the UICC client verify callback if it fails,
do we not get a response to that callback even if UICC fails ?
Regards
Andreas
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH 16/18] isimodem: sms updated with wgmodem2.5
2011-02-16 14:47 ` Andreas WESTIN
@ 2011-02-17 10:30 ` Aki Niemi
0 siblings, 0 replies; 38+ messages in thread
From: Aki Niemi @ 2011-02-17 10:30 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 586 bytes --]
Hi Andreas,
2011/2/16 Andreas WESTIN <andreas.westin@stericsson.com>:
>> This UICC stuff seems to be leftovers form patch 8/18.
>
> Well they are related to SMS, debug prints. But yes they are also UICC. Do
> you want them in patch 8 ?
That would be my preference. That is, a patch to bring in the PN_UICC
codepoints and debugs, then separate patches for implementations using
those new codepoints.
> PN_SIM client is created in the UICC client verify callback if it fails, do
> we not get a response to that callback even if UICC fails ?
Ah, right.
Cheers,
Aki
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 17/18] isimodem: CBS for wgmodem2.5
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (15 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 16/18] isimodem: sms updated with wgmodem2.5 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
2011-02-16 16:10 ` Denis Kenzior
2011-02-15 12:31 ` [PATCH 18/18] isimodem: initial support for UICC phonebook Andreas Westin
17 siblings, 1 reply; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 14847 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
set and clear topics support added
---
drivers/isimodem/cbs.c | 425 +++++++++++++++++++++++++++++++++++++++++-----
drivers/isimodem/debug.c | 4 +
drivers/isimodem/sms.h | 7 +-
3 files changed, 394 insertions(+), 42 deletions(-)
diff --git a/drivers/isimodem/cbs.c b/drivers/isimodem/cbs.c
index b969c1f..93219e2 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,15 @@
struct cbs_data {
GIsiClient *client;
+ uint8_t subscription_nr;
};
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 +93,299 @@ 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;
+ }
+
+ 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++;
+ }
+
+ 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];
+ GIsiModem *modem;
+
+ 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;
+
+ modem = g_isi_client_modem(cd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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);
+ GIsiModem *modem;
+
+ 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;
+
+ modem = g_isi_client_modem(cd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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 +416,71 @@ 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;
+ GIsiModem *modem;
- 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);
+
+ modem = g_isi_client_modem(cd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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 +489,60 @@ 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;
+ GIsiModem *modem;
if (cd == NULL)
return;
+ modem = g_isi_client_modem(cd->client);
+
+ if (g_isi_modem_version_major(modem) == 2 &&
+ g_isi_modem_version_minor(modem) >= 0) {
+ 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 +551,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] 38+ messages in thread* Re: [PATCH 17/18] isimodem: CBS for wgmodem2.5
2011-02-15 12:31 ` [PATCH 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
@ 2011-02-16 16:10 ` Denis Kenzior
2011-02-17 12:47 ` Andreas WESTIN
0 siblings, 1 reply; 38+ messages in thread
From: Denis Kenzior @ 2011-02-16 16:10 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1997 bytes --]
Hi Andreas,
> +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;
> + }
> +
> + 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++;
> + }
> +
> + topics++;
> + }
> +}
> +
Have you thought of adapting cbs_extract_topic_ranges function for all
of this somehow?
Regards,
-Denis
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 18/18] isimodem: initial support for UICC phonebook
2011-02-15 12:30 [PATCH 00/18] wgmodem2.5 support Andreas Westin
` (16 preceding siblings ...)
2011-02-15 12:31 ` [PATCH 17/18] isimodem: CBS for wgmodem2.5 Andreas Westin
@ 2011-02-15 12:31 ` Andreas Westin
17 siblings, 0 replies; 38+ messages in thread
From: Andreas Westin @ 2011-02-15 12:31 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 33315 bytes --]
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
---
drivers/isimodem/phonebook.c | 1241 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 1210 insertions(+), 31 deletions(-)
diff --git a/drivers/isimodem/phonebook.c b/drivers/isimodem/phonebook.c
index 1f92d37..dfb76ed 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,82 @@ 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;
+ struct ofono_sim_driver *sim_func;
+ 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 +295,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,50 +754,711 @@ 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;
+
+ if (cbd_outer == NULL)
+ goto out;
+
+ file_info = cbd_outer->user;
+ cbd = cbd_outer->data;
+
+ 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(file_info, sdata, length, pb);
+
+ if (file_info != NULL) {
+ DBG("Reading extension file %04X, record %d",
+ file_info->file_id, file_info->record);
+ pbd->sim_func->read_file_linear(get_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);
+ pbd->sim_func->read_file_linear(get_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;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+ file_info = NULL;
+
+ if (pbd || error->type != OFONO_ERROR_TYPE_NO_ERROR ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ pbd->sim_func->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);
+ pbd->sim_func->read_file_linear(get_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;
+
+ if (pbd == NULL || file_info == NULL || cbd == NULL)
+ return;
+
+ 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 (pbd->sim_func->read_file_linear == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_linear(get_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 (pbd->sim_func->read_file_cyclic == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_cyclic(get_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 (pbd->sim_func->read_file_transparent == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_transparent(get_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;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ 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);
+ pbd->sim_func->read_file_info(get_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;
+
+ 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;
+
+ 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);
+ pbd->sim_func->read_file_linear(get_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;
+
+ pbd->sim_func->read_file_info(get_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;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+ goto error;
+
+ if (pbd->sim_func->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;
+ pbd->sim_func->read_file_linear(get_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);
- 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()) {
+ case UICC_APPL_TYPE_ICC_SIM:
+ DBG("SIM application");
+ pbd->sim_func->read_file_info(get_sim(),
+ SIM_EFADN_FILEID,
+ pb_adn_sim_info_cb,
+ cbd);
+ break;
+ case UICC_APPL_TYPE_UICC_USIM:
+ DBG("USIM application");
+ pbd->sim_func->read_file_info(get_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 +1473,25 @@ 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 = get_pn_uicc_client(modem, PN_UICC);
+ if (data->primary == NULL) {
+ g_free(data);
+ return -ENOMEM;
+ }
+
+ data->sim_func = get_sim_driver_func();
+
+ 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 +1500,20 @@ 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;
+ if (g_isi_client_resource(data->client) == PN_UICC)
+ pn_uicc_client_destroy(data->client);
+ else
+ g_isi_client_destroy(data->client);
- g_isi_client_destroy(data->client);
g_free(data);
}
--
1.7.3.5
^ permalink raw reply related [flat|nested] 38+ messages in thread