summaryrefslogtreecommitdiff
path: root/drivers/isimodem
diff options
context:
space:
mode:
authorAki Niemi <aki.niemi@nokia.com>2011-04-12 19:48:56 +0300
committerAki Niemi <aki.niemi@nokia.com>2011-04-12 20:39:19 +0300
commitc33853ecf36e1b5cd1d14f04e389fdb8296f9189 (patch)
treedf0c0ba9b02327f6fc3d23f49351baf4a640d743 /drivers/isimodem
parentec1c8a2ec667eccd6d5cfce362113f66cd1ea276 (diff)
isimodem: Update SMS driver for wgmodem2.5
Based on patches from: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
Diffstat (limited to 'drivers/isimodem')
-rw-r--r--drivers/isimodem/sms.c694
1 files changed, 541 insertions, 153 deletions
diff --git a/drivers/isimodem/sms.c b/drivers/isimodem/sms.c
index edf99a78..5b628e8f 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 "sim.h"
#include "debug.h"
/* This is a straightforward copy of the EF_smsp structure */
@@ -102,23 +104,71 @@ struct sms_common {
struct sms_data {
GIsiClient *client;
GIsiClient *sim;
+ GIsiVersion version;
struct sim_efsmsp params;
};
-static gboolean check_sim_status(const GIsiMessage *msg, uint8_t msgid,
- uint8_t service)
+static uint8_t bearer_to_cs_pref(int bearer)
+{
+ switch (bearer) {
+ case 0:
+ return SMS_ROUTE_NOT_AVAILABLE;
+ case 1:
+ return SMS_ROUTE_PRIORITY_1;
+ case 2:
+ return SMS_ROUTE_PRIORITY_2;
+ case 3:
+ return SMS_ROUTE_PRIORITY_1;
+ }
+
+ return SMS_ROUTE_NOT_AVAILABLE;
+}
+
+static uint8_t bearer_to_ps_pref(int bearer)
+{
+ switch (bearer) {
+ case 0:
+ return SMS_ROUTE_PRIORITY_1;
+ case 1:
+ return SMS_ROUTE_NOT_AVAILABLE;
+ case 2:
+ return SMS_ROUTE_PRIORITY_1;
+ case 3:
+ return SMS_ROUTE_PRIORITY_2;
+ }
+
+ return SMS_ROUTE_NOT_AVAILABLE;
+}
+
+static int cs_ps_pref_to_bearer(uint8_t cs, uint8_t ps)
+{
+ if (cs == SMS_ROUTE_NOT_AVAILABLE && ps == SMS_ROUTE_PRIORITY_1)
+ return 0;
+
+ if (cs == SMS_ROUTE_PRIORITY_1 && ps == SMS_ROUTE_NOT_AVAILABLE)
+ return 1;
+
+ if (cs == SMS_ROUTE_PRIORITY_2 && ps == SMS_ROUTE_PRIORITY_1)
+ return 2;
+
+ if (cs == SMS_ROUTE_PRIORITY_1 && ps == SMS_ROUTE_PRIORITY_2)
+ return 3;
+
+ return 0;
+}
+
+static gboolean check_sim(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)));
+ DBG("Error: %s", g_isi_msg_strerror(msg));
return FALSE;
}
if (g_isi_msg_id(msg) != msgid) {
- DBG("Unexpected msg: %s",
- sms_message_id_name(g_isi_msg_id(msg)));
+ DBG("Unexpected msg: %s", sms_message_id_name(g_isi_msg_id(msg)));
return FALSE;
}
@@ -141,12 +191,23 @@ 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(const GIsiMessage *msg, uint8_t msgid, int expect)
{
uint8_t cause;
+ int pos;
+
+ /*
+ * Quirk for the cause code position in the response. More
+ * recent versions of the API use 16bit subblock IDs, causing
+ * the cause to be bumped forward by one byte.
+ */
+ if (ISI_VERSION_AT_LEAST(msg->version, 9, 1))
+ pos = 1;
+ else
+ pos = 0;
if (g_isi_msg_error(msg) < 0) {
- DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+ DBG("Error: %s", g_isi_msg_strerror(msg));
return FALSE;
}
@@ -156,12 +217,15 @@ static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
return FALSE;
}
- if (!g_isi_msg_data_get_byte(msg, 0, &cause)) {
+ if (expect == -1)
+ return TRUE;
+
+ if (!g_isi_msg_data_get_byte(msg, pos, &cause)) {
DBG("Unable to parse cause");
return FALSE;
}
- if (cause == SMS_OK)
+ if (cause == expect)
return TRUE;
if (cause == SMS_ERR_PP_RESERVED) {
@@ -178,7 +242,7 @@ static gboolean check_sms_status(const GIsiMessage *msg, uint8_t msgid)
return FALSE;
}
-static void sca_query_resp_cb(const GIsiMessage *msg, void *data)
+static void sca_sim_query_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
struct ofono_sms *sms = cbd->user;
@@ -190,7 +254,7 @@ static void sca_query_resp_cb(const GIsiMessage *msg, void *data)
size_t len = sizeof(struct sms_params);
uint8_t bcd_len;
- if (!check_sim_status(msg, SIM_SMS_RESP, READ_PARAMETER))
+ if (!check_sim(msg, SIM_SMS_RESP, READ_PARAMETER))
goto error;
if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &info, len))
@@ -236,23 +300,28 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
-static void isi_sca_query(struct ofono_sms *sms,
- ofono_sms_sca_query_cb_t cb, void *data)
+static gboolean sca_sim_query(GIsiClient *client, void *data, GDestroyNotify notify)
{
- 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[] = {
SIM_SMS_REQ,
READ_PARAMETER,
1, /* Location, default is 1 */
};
- if (cbd == NULL || sd == NULL || sd->sim == NULL)
+ return g_isi_client_send(client, msg, sizeof(msg), sca_sim_query_resp_cb,
+ data, notify);
+}
+
+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);
+
+ if (cbd == NULL || sd->sim == NULL)
goto error;
- if (g_isi_client_send(sd->sim, msg, sizeof(msg),
- sca_query_resp_cb, cbd, g_free))
+ if (sca_sim_query(sd->sim, cbd, g_free))
return;
error:
@@ -260,12 +329,12 @@ error:
g_free(cbd);
}
-static void sca_set_resp_cb(const GIsiMessage *msg, void *data)
+static void sca_sim_set_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
ofono_sms_sca_set_cb_t cb = cbd->cb;
- if (!check_sim_status(msg, SIM_SMS_RESP, UPDATE_PARAMETER)) {
+ if (!check_sim(msg, SIM_SMS_RESP, UPDATE_PARAMETER)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
@@ -273,36 +342,43 @@ static void sca_set_resp_cb(const GIsiMessage *msg, void *data)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
-static void isi_sca_set(struct ofono_sms *sms,
- const struct ofono_phone_number *sca,
- ofono_sms_sca_set_cb_t cb, void *data)
+static gboolean sca_sim_set(GIsiClient *client, struct sim_efsmsp *params,
+ const struct ofono_phone_number *sca, void *data,
+ GDestroyNotify notify)
{
- 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] = {
{ msg, sizeof(msg) },
- { &sd->params, sizeof(sd->params) },
+ { params, sizeof(struct sim_efsmsp) },
};
+ uint8_t *bcd;
- if (cbd == NULL || sd == NULL || sd->sim == NULL)
- goto error;
-
- bcd = sd->params.sca;
- sd->params.absent &= ~0x02;
+ bcd = params->sca;
+ 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))
+ return g_isi_client_vsend(client, iov, 2, sca_sim_set_resp_cb,
+ data, notify);
+}
+
+static void isi_sca_set(struct ofono_sms *sms,
+ const struct ofono_phone_number *sca,
+ ofono_sms_sca_set_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);
+
+ if (cbd == NULL || sd->sim == NULL)
+ goto error;
+
+ if (sca_sim_set(sd->sim, &sd->params, sca, cbd, g_free))
return;
error:
@@ -310,7 +386,46 @@ error:
g_free(cbd);
}
-static void submit_resp_cb(const GIsiMessage *msg, void *data)
+static void submit_failure_debug(struct sms_report *report)
+{
+ const char *cause;
+
+ if (report->type == SMS_CAUSE_TYPE_COMMON)
+ cause = sms_isi_cause_name(report->cause);
+ else
+ cause = sms_gsm_cause_name(report->cause);
+
+ DBG("Message 0x%02"PRIx8" failed: %s", report->ref, cause);
+}
+
+static void submit_tpdu_resp_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);
+
+ if (!check_sms(msg, SMS_MESSAGE_SEND_RESP, -1))
+ goto error;
+
+ if (g_isi_msg_data_len(msg) < len)
+ 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;
+ }
+
+ submit_failure_debug(report);
+
+error:
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+static void submit_gsm_tpdu_resp_cb(const GIsiMessage *msg, void *data)
{
struct isi_cb_data *cbd = data;
ofono_sms_submit_cb_t cb = cbd->cb;
@@ -318,7 +433,7 @@ static void submit_resp_cb(const GIsiMessage *msg, void *data)
size_t len = sizeof(struct sms_report);
GIsiSubBlockIter iter;
- if (!check_sms_status(msg, SMS_MESSAGE_SEND_RESP))
+ if (!check_sms(msg, SMS_MESSAGE_SEND_RESP, -1))
goto error;
for (g_isi_sb_iter_init(&iter, msg, 2);
@@ -331,101 +446,238 @@ static void submit_resp_cb(const GIsiMessage *msg, void *data)
if (!g_isi_sb_iter_get_struct(&iter, (void **) &report, len, 2))
goto error;
- if (report->cause != SMS_OK)
- goto error;
+ if (report->type == SMS_CAUSE_TYPE_COMMON &&
+ report->cause == SMS_OK) {
+ CALLBACK_WITH_SUCCESS(cb, report->ref, cbd->data);
+ return;
+ }
- CALLBACK_WITH_SUCCESS(cb, report->ref, cbd->data);
- return;
+ submit_failure_debug(report);
}
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
-static void isi_submit(struct ofono_sms *sms, unsigned char *pdu,
- int pdu_len, int tpdu_len, int mms,
- ofono_sms_submit_cb_t cb, void *data)
+static gboolean submit_tpdu(GIsiClient *client, unsigned char *pdu, int pdu_len,
+ int tpdu_len, int mms, void *data,
+ GDestroyNotify notify)
{
- struct sms_data *sd = ofono_sms_get_data(sms);
- struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
+ size_t tpdu_sb_len = ALIGN4(6 + tpdu_len);
+ size_t tpdu_pad_len = tpdu_sb_len - (6 + tpdu_len);
+
+ uint8_t hdr[] = {
+ SMS_MESSAGE_SEND_REQ,
+ mms, /* More messages to send */
+ SMS_ROUTE_DEFAULT,
+ 0, /* Repeated message */
+ 0, 0, /* Filler */
+ 2, /* Subblock count */
+ ISI_16BIT(SMS_SB_TPDU),
+ ISI_16BIT(tpdu_sb_len),
+ tpdu_len,
+ 0, /* Filler */
+ /* Databytes aligned to next 32bit boundary */
+ };
+ uint8_t params[] = {
+ ISI_16BIT(SMS_SB_SMS_PARAMETERS),
+ ISI_16BIT(8), /* Subblock length */
+ 1, /* Location number */
+ SMS_PI_SERVICE_CENTER_ADDRESS,
+ 0, 0, /* Filler */
+ };
+ uint8_t padding[4] = { 0 };
+ struct iovec iov[4] = {
+ { hdr, sizeof(hdr) },
+ { pdu + pdu_len - tpdu_len, tpdu_len },
+ { padding, tpdu_pad_len },
+ { params, sizeof(params) },
+ };
- uint8_t use_sca = pdu_len - tpdu_len != 1 || pdu[0] == 0;
+ /* FIXME: Missing SB for SCA if provided */
- 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;
+ return g_isi_client_vsend_with_timeout(client, iov, 4, SMS_TIMEOUT,
+ submit_tpdu_resp_cb, data,
+ notify);
+}
- uint8_t sca_sb_len = use_sca ? 16 : 0;
+static gboolean submit_gsm_tpdu(GIsiClient *client, unsigned char *pdu,
+ int pdu_len, int tpdu_len, int mms,
+ void *data, GDestroyNotify notify)
+{
+ uint8_t use_sca = (pdu_len - tpdu_len) > 1;
+ size_t sca_sb_len = use_sca ? 16 : 0;
+ size_t tpdu_sb_len = ALIGN4(4 + tpdu_len);
+ size_t tpdu_pad_len = tpdu_sb_len - (4 + tpdu_len);
uint8_t msg[] = {
SMS_MESSAGE_SEND_REQ,
- mms,
+ mms, /* More messages to send */
SMS_ROUTE_CS_PREF,
- 0, /* Is this a re-send? */
+ 0, /* Repeated message */
SMS_SENDER_ANY,
SMS_TYPE_TEXT_MESSAGE,
- 1, /* Sub blocks */
+ 1, /* Subblock count */
SMS_GSM_TPDU,
- 4 + tpdu_sb_len + sca_sb_len,
- 0, /* Filler */
+ 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 */
+ /* Databytes aligned to next 32bit boundary */
};
-
- static uint8_t filler[4];
-
uint8_t sca_sb[16] = {
SMS_ADDRESS,
- 16,
+ 16, /* Subblock length */
SMS_GSM_0411_ADDRESS,
- 0,
+ 0, /* Filled in later */
};
-
+ uint8_t padding[4] = { 0 };
struct iovec iov[4] = {
{ msg, sizeof(msg) },
- { tpdu, tpdu_len },
- { filler, filler_len },
+ { pdu + pdu_len - tpdu_len, tpdu_len },
+ { padding, tpdu_pad_len },
{ sca_sb, sca_sb_len },
};
- if (cbd == NULL || sd == NULL)
- goto error;
-
if (use_sca) {
sca_sb[3] = pdu_len - tpdu_len;
- memcpy(sca_sb + 4, pdu, sca_sb[3]);
+ memcpy(sca_sb + 4, pdu, pdu_len - tpdu_len);
}
/*
* 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;
+ return g_isi_client_vsend_with_timeout(client, iov, 4, SMS_TIMEOUT + 5,
+ submit_gsm_tpdu_resp_cb, data,
+ notify);
+}
+
+static void isi_submit(struct ofono_sms *sms, unsigned char *pdu,
+ int pdu_len, int tpdu_len, int mms,
+ ofono_sms_submit_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);
+
+ if (cbd == NULL)
+ goto error;
+
+ if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1)) {
+ if (submit_tpdu(sd->client, pdu, pdu_len, tpdu_len, mms,
+ cbd, g_free))
+ return;
+ } else {
+ if (submit_gsm_tpdu(sd->client, pdu, pdu_len, tpdu_len, mms,
+ cbd, g_free))
+ return;
+ }
error:
CALLBACK_WITH_FAILURE(cb, -1, data);
g_free(cbd);
}
+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;
+ GIsiSubBlockIter iter;
+ uint8_t sb, cs, ps;
+
+ if (!check_sms(msg, SMS_SETTINGS_READ_RESP, SMS_OK))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 1, &sb))
+ goto error;
+
+ for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, sb);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != SMS_SB_ROUTE_INFO)
+ continue;
+
+ if (!g_isi_msg_data_get_byte(msg, 5, &cs))
+ goto error;
+
+ if (!g_isi_msg_data_get_byte(msg, 6, &ps))
+ goto error;
+
+ CALLBACK_WITH_SUCCESS(cb, cs_ps_pref_to_bearer(cs, ps),
+ cbd->data);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, 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);
+ const uint8_t msg[] = {
+ SMS_SETTINGS_READ_REQ,
+ SMS_SETTING_TYPE_ROUTE,
+ 0,
+ };
+
+ DBG("");
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg), bearer_query_resp_cb,
+ cbd, g_free))
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, data);
+ g_free(cbd);
+}
+
+static void bearer_set_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ ofono_sms_bearer_set_cb_t cb = cbd->cb;
+
+ if (check_sms(msg, SMS_SETTINGS_UPDATE_RESP, SMS_OK))
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ else
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
}
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);
+ const uint8_t msg[] = {
+ SMS_SETTINGS_UPDATE_REQ,
+ SMS_SETTING_TYPE_ROUTE,
+ 1, /* Subblock count */
+ ISI_16BIT(SMS_SB_ROUTE_INFO),
+ ISI_16BIT(8), /* Subblock length */
+ bearer_to_cs_pref(bearer), /* CS priority */
+ bearer_to_ps_pref(bearer), /* PS priority */
+ 0, 0,
+ };
+
+ if (cbd == NULL)
+ goto error;
+
+ if (g_isi_client_send(sd->client, msg, sizeof(msg), bearer_set_resp_cb,
+ cbd, g_free))
+ return;
+
+error:
CALLBACK_WITH_FAILURE(cb, data);
+ g_free(cbd);
}
static void send_status_ind_cb(const GIsiMessage *msg, void *data)
@@ -449,75 +701,88 @@ static void send_status_ind_cb(const GIsiMessage *msg, void *data)
DBG("TODO: Status notification");
}
-static void report_resp_cb(const GIsiMessage *msg, void *data)
+static void gsm_report_resp_cb(const GIsiMessage *msg, void *data)
{
- uint8_t cause;
-
- if (g_isi_msg_error(msg) < 0)
- return;
-
- if (g_isi_msg_id(msg) != SMS_GSM_RECEIVED_PP_REPORT_RESP)
- return;
-
- if (!g_isi_msg_data_get_byte(msg, 0, &cause))
- return;
-
- DBG("Report resp cause=0x%"PRIx8, cause);
+ if (!check_sms(msg, SMS_GSM_RECEIVED_PP_REPORT_RESP, SMS_OK))
+ DBG("Sending report failed");
}
-static gboolean send_deliver_report(GIsiClient *client, gboolean success)
+static void report_resp_cb(const GIsiMessage *msg, void *data)
{
- uint8_t cause_type = !success ? SMS_CAUSE_TYPE_GSM : 0;
- uint8_t cause = !success ? SMS_GSM_ERR_MEMORY_CAPACITY_EXC : 0;
+ if (!check_sms(msg, SMS_RECEIVED_MSG_REPORT_RESP, SMS_OK))
+ DBG("Sending report failed");
+}
- uint8_t msg[] = {
+static gboolean send_gsm_deliver_report(GIsiClient *client, gboolean success,
+ void *data, GDestroyNotify destroy)
+{
+ const uint8_t msg[] = {
SMS_GSM_RECEIVED_PP_REPORT_REQ,
- cause_type, /* Cause type */
- cause, /* SMS cause */
+ success ? 0 : SMS_CAUSE_TYPE_GSM,
+ success ? SMS_OK : SMS_GSM_ERR_MEMORY_CAPACITY_EXC,
0, 0, 0, /* Filler */
1, /* Sub blocks */
SMS_GSM_DELIVER_REPORT,
- 8,
+ 8, /* Subblock length */
0, /* Message parameters */
0, /* Cause type */
0, 0, 0, /* Filler */
0, /* Sub blocks */
};
- size_t len = sizeof(msg);
- return g_isi_client_send(client, msg, len, report_resp_cb, NULL, NULL);
+ return g_isi_client_send(client, msg, sizeof(msg), gsm_report_resp_cb,
+ data, destroy);
+}
+
+static gboolean send_deliver_report(GIsiClient *client, gboolean success,
+ void *data, GDestroyNotify destroy)
+{
+ const uint8_t msg[] = {
+ SMS_RECEIVED_MSG_REPORT_REQ,
+ success ? 0 : SMS_CAUSE_TYPE_GSM,
+ success ? SMS_OK : SMS_GSM_ERR_MEMORY_CAPACITY_EXC,
+ 0, 0, 0, /* Filler */
+ 0, /* Subblocks */
+ };
+
+ return g_isi_client_send(client, msg, sizeof(msg), report_resp_cb,
+ data, destroy);
}
-static gboolean parse_sms_address(GIsiSubBlockIter *iter, struct sms_addr *add)
+static gboolean parse_sms_address(GIsiSubBlockIter *iter, unsigned offset,
+ struct sms_addr *add)
{
add->data = NULL;
- if (!g_isi_sb_iter_get_byte(iter, &add->type, 2))
+ if (!g_isi_sb_iter_get_byte(iter, &add->type, offset))
return FALSE;
- if (!g_isi_sb_iter_get_byte(iter, &add->len, 3))
+ if (!g_isi_sb_iter_get_byte(iter, &add->len, offset + 1))
return FALSE;
if (add->len == 0)
return FALSE;
- if (!g_isi_sb_iter_get_struct(iter, (void **) &add->data, add->len, 4))
+ if (!g_isi_sb_iter_get_struct(iter, (void **) &add->data, add->len,
+ offset + 2))
return FALSE;
return TRUE;
}
-static gboolean parse_sms_tpdu(GIsiSubBlockIter *iter, struct sms_common *com)
+static gboolean parse_sms_tpdu(GIsiSubBlockIter *iter, unsigned offset,
+ struct sms_common *com)
{
com->data = NULL;
- if (!g_isi_sb_iter_get_byte(iter, &com->len, 2))
+ if (!g_isi_sb_iter_get_byte(iter, &com->len, offset))
return FALSE;
if (com->len == 0)
return FALSE;
- if (!g_isi_sb_iter_get_struct(iter, (void **) &com->data, com->len, 4))
+ if (!g_isi_sb_iter_get_struct(iter, (void **) &com->data, com->len,
+ offset + 2))
return FALSE;
return TRUE;
@@ -535,7 +800,7 @@ static gboolean parse_gsm_tpdu(GIsiSubBlockIter *parent, struct sms_addr *add,
switch (g_isi_sb_iter_get_id(&iter)) {
case SMS_ADDRESS:
- if (!parse_sms_address(&iter, add))
+ if (!parse_sms_address(&iter, 2, add))
return FALSE;
if (add->type != SMS_GSM_0411_ADDRESS)
@@ -545,7 +810,7 @@ static gboolean parse_gsm_tpdu(GIsiSubBlockIter *parent, struct sms_addr *add,
case SMS_COMMON_DATA:
- if (!parse_sms_tpdu(&iter, com))
+ if (!parse_sms_tpdu(&iter, 2, com))
return FALSE;
break;
@@ -586,29 +851,96 @@ static void routing_ntf_cb(const GIsiMessage *msg, void *data)
memcpy(pdu, addr.data, addr.len);
memcpy(pdu + addr.len, tpdu.data, tpdu.len);
- ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
+ /* 23.040 9.2.3.1 */
+ if ((tpdu.data[0] & 0x03) == 0x02)
+ ofono_sms_status_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
+ else
+ ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
- /*
- * FIXME: We should not ack the DELIVER unless it has been
- * reliably stored, i.e., written to disk. Currently, there is
- * no such indication from core, so we just blindly trust that
- * it did The Right Thing here.
- */
- send_deliver_report(sd->client, TRUE);
+ send_gsm_deliver_report(sd->client, TRUE, NULL, NULL);
}
-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);
+ struct sms_common tpdu;
+ struct sms_addr addr;
+ GIsiSubBlockIter iter;
- if (!check_sms_status(msg, SMS_PP_ROUTING_RESP)) {
- ofono_sms_remove(sms);
+ uint8_t pdu[176];
+ uint8_t sbcount;
+
+ DBG("");
+
+ if (g_isi_msg_id(msg) != SMS_RECEIVED_MSG_IND)
+ return;
+
+ if (!g_isi_msg_data_get_byte(msg, 1, &sbcount))
return;
+
+ 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)) {
+ case SMS_ADDRESS:
+
+ if (!parse_sms_address(&iter, 4, &addr))
+ return;
+
+ if (addr.type != SMS_SMSC_ADDRESS)
+ return;
+
+ break;
+
+ case SMS_SB_TPDU:
+
+ if (!parse_sms_tpdu(&iter, 4, &tpdu))
+ return;
+
+ break;
+ }
}
- g_isi_client_ntf_subscribe(sd->client, SMS_PP_ROUTING_NTF,
- routing_ntf_cb, sms);
+ if (tpdu.data == NULL || addr.data == NULL ||
+ tpdu.len + addr.len > sizeof(pdu))
+ return;
+
+ memcpy(pdu, addr.data, addr.len);
+ memcpy(pdu + addr.len, tpdu.data, tpdu.len);
+
+ /* 23.040 9.2.3.1 */
+ if ((tpdu.data[0] & 0x03) == 0x02)
+ ofono_sms_status_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
+ else
+ ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
+
+ send_deliver_report(sd->client, TRUE, NULL, NULL);
+}
+
+static void reception_resp_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_sms *sms = data;
+
+ if (sms == NULL)
+ return;
+
+ if (!check_sms(msg, SMS_RECEIVE_MESSAGE_RESP, SMS_RECEPTION_ACTIVE))
+ 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(msg, SMS_PP_ROUTING_RESP, SMS_OK))
+ return;
ofono_sms_register(sms);
}
@@ -618,28 +950,78 @@ 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[] = {
+ if (sd == NULL)
+ return;
+
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Unable to bootstrap SIM service");
+
+ g_isi_client_destroy(sd->sim);
+ sd->sim = NULL;
+ return;
+ }
+
+ ISI_RESOURCE_DBG(msg);
+}
+
+static gboolean set_routing(GIsiClient *client, void *data,
+ GDestroyNotify destroy)
+{
+ const uint8_t msg[] = {
SMS_PP_ROUTING_REQ,
SMS_ROUTING_SET,
- 0x01, /* Sub-block count */
+ 1, /* Sub-block count */
SMS_GSM_ROUTING,
- 0x08, /* Sub-block length */
+ 8, /* Sub-block length */
SMS_GSM_TPDU_ROUTING,
SMS_GSM_MT_ALL_TYPE,
- 0x00, 0x00, 0x00, /* Filler */
- 0x00 /* Sub-sub-block count */
+ 0, 0, 0, /* Filler */
+ 0, /* Sub-sub-block count */
};
- size_t len = sizeof(req);
- if (g_isi_msg_error(msg) < 0) {
- DBG("unable to find SIM resource");
- g_isi_client_destroy(sd->sim);
- sd->sim = NULL;
- }
+ return g_isi_client_send(client, msg, sizeof(msg), routing_resp_cb,
+ data, destroy);
+}
- 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 gboolean unset_routing(GIsiClient *client)
+{
+ 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,
+ 0, 0, 0, /* Filler */
+ 0, /* Sub-sub-block count */
+ };
+
+ return g_isi_client_send(client, msg, sizeof(msg), NULL, NULL, NULL);
+}
+
+static gboolean activate_reception(GIsiClient *client, void *data,
+ GDestroyNotify destroy)
+{
+ const uint8_t msg[] = {
+ SMS_RECEIVE_MESSAGE_REQ,
+ SMS_RECEPTION_ACTIVATE,
+ 0,
+ };
+
+ return g_isi_client_send(client, msg, sizeof(msg), reception_resp_cb,
+ data, destroy);
+}
+
+static gboolean deactivate_reception(GIsiClient *client)
+{
+ const uint8_t msg[] = {
+ SMS_RECEIVE_MESSAGE_REQ,
+ SMS_RECEPTION_DEACTIVATE,
+ 0,
+ };
+
+ return g_isi_client_send(client, msg, sizeof(msg), NULL, NULL, NULL);
}
static void sms_reachable_cb(const GIsiMessage *msg, void *data)
@@ -653,8 +1035,19 @@ static void sms_reachable_cb(const GIsiMessage *msg, void *data)
return;
}
+ if (sd == NULL)
+ return;
+
ISI_RESOURCE_DBG(msg);
+ sd->version.major = g_isi_msg_version_major(msg);
+ sd->version.minor = g_isi_msg_version_minor(msg);
+
+ if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1))
+ activate_reception(sd->client, sms, NULL);
+ else
+ set_routing(sd->client, sms, NULL);
+
g_isi_client_verify(sd->sim, sim_reachable_cb, sms, NULL);
}
@@ -678,11 +1071,14 @@ static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
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);
return 0;
@@ -697,28 +1093,20 @@ static void isi_sms_remove(struct ofono_sms *sms)
{
struct sms_data *sd = ofono_sms_get_data(sms);
- const uint8_t msg[] = {
- SMS_PP_ROUTING_REQ,
- SMS_ROUTING_RELEASE,
- 0x01, /* Sub-block count */
- SMS_GSM_ROUTING,
- 0x08, /* Sub-block length */
- SMS_GSM_TPDU_ROUTING,
- SMS_GSM_MT_ALL_TYPE,
- 0x00, 0x00, 0x00, /* Filler */
- 0x00 /* Sub-sub-block count */
- };
-
- ofono_sms_set_data(sms, NULL);
-
if (sd == NULL)
return;
+ ofono_sms_set_data(sms, NULL);
+
/*
* Send a promiscuous routing release, so as not to
* hog resources unnecessarily after being removed
*/
- g_isi_client_send(sd->client, msg, sizeof(msg), NULL, NULL, NULL);
+ if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1))
+ deactivate_reception(sd->client);
+ else
+ unset_routing(sd->client);
+
g_isi_client_destroy(sd->client);
g_isi_client_destroy(sd->sim);
g_free(sd);