Hi Philippe,
On 05/20/2011 11:26 AM, Philippe Nunes wrote:
---
src/stk.c | 426 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 425 insertions(+), 1 deletions(-)
This patch no longer applies. Please rebase and resubmit. Also, can I
ask you to break this patch up into several, e.g. one for Open Channel,
one for Close Channel, etc. This will make it much easier for me to review.
diff --git a/src/stk.c b/src/stk.c
index 8214b65..fb376a6 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -41,6 +41,7 @@
#include "smsutil.h"
#include "stkutil.h"
#include "stkagent.h"
+#include "gprs.h"
#include "util.h"
static GSList *g_drivers = NULL;
@@ -79,6 +80,11 @@ struct ofono_stk {
__ofono_sms_sim_download_cb_t sms_pp_cb;
void *sms_pp_userdata;
+ struct stk_channel channel;
+ struct stk_channel_data rx_buffer;
+ struct stk_channel_data tx_buffer;
Are you sure you need these buffers? At least the RX buffer can
probably be ignored since you can always use the kernel socket buffer
instead. Copying from the kernel buffer into your own buffer just to
copy it into SIM's buffer seems like busywork.
The TX buffer is arguable, you might want to use non-blocking IO, but in
that case I would use a ring_buffer from GAtChat.
+ gboolean link_on_demand;
+ struct ofono_gprs *gprs;
};
struct envelope_op {
@@ -104,6 +110,13 @@ static void timers_update(struct ofono_stk *stk);
result.additional_len = sizeof(addn_info); \
result.additional = addn_info; \
+/*
+ * According the structure and coding of the Terminal response defined in
+ * TS 102 223 section 6.8, the maximum number of bytes possible for the channel
+ * data object is 243
+ */
+#define CHANNEL_DATA_OBJECT_MAX_LENGTH 243
+
static int stk_respond(struct ofono_stk *stk, struct stk_response *rsp,
ofono_stk_generic_cb_t cb)
{
@@ -474,12 +487,43 @@ static void emit_menu_changed(struct ofono_stk *stk)
g_dbus_send_message(conn, signal);
}
+static void stk_close_channel(struct ofono_stk *stk)
+{
+ /*
+ * TODO
+ * Deactivate and remove PDP context
+ * Send the Terminal Response once the PDP context is deactivated
+ */
+
+ /* Temporary implementation */
+ g_free(stk->rx_buffer.data.array);
+ g_free(stk->tx_buffer.data.array);
+ stk->rx_buffer.data.array = NULL;
+ stk->tx_buffer.data.array = NULL;
+
+ stk->channel.id = 0;
+ stk->channel.status = STK_CHANNEL_PACKET_DATA_SERVICE_NOT_ACTIVATED;
+
+ if (stk->pending_cmd &&
Would this function ever be called if pending_cmd is NULL?
+ stk->pending_cmd->type ==
+ STK_COMMAND_TYPE_CLOSE_CHANNEL)
+ send_simple_response(stk, STK_RESULT_TYPE_SUCCESS);
+}
+
static void user_termination_cb(enum stk_agent_result result, void *user_data)
{
struct ofono_stk *stk = user_data;
- if (result == STK_AGENT_RESULT_TERMINATE)
+ if (result != STK_AGENT_RESULT_TERMINATE)
+ return;
+
+ if (stk->pending_cmd) {
+ stk->cancel_cmd(stk);
You can't actually do this since the agent does not support calling
stk_agent_request_cancel from within a callback.
send_simple_response(stk, STK_RESULT_TYPE_USER_TERMINATED);
+ }
+
+ if (stk->channel.id)
+ stk_close_channel(stk);
}
static void stk_alpha_id_set(struct ofono_stk *stk,
@@ -510,6 +554,147 @@ static void stk_alpha_id_unset(struct ofono_stk *stk)
stk_agent_request_cancel(stk->current_agent);
}
+
+static void stk_open_channel(struct ofono_stk *stk)
+{
+ const struct stk_command_open_channel *oc;
+ struct stk_response rsp;
+ struct ofono_error failure = { .type = OFONO_ERROR_TYPE_FAILURE };
+
+ if (stk->pending_cmd == NULL ||
+ stk->pending_cmd->type != STK_COMMAND_TYPE_OPEN_CHANNEL)
doc/coding-style.txt item M4
+ return;
+
+ oc = &stk->pending_cmd->open_channel;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+
+ stk->rx_buffer.data.array = g_try_malloc(oc->buf_size);
+ if (stk->rx_buffer.data.array == NULL) {
+ unsigned char no_cause_result[] = { 0x00 };
+
+ ADD_ERROR_RESULT(rsp.result, STK_RESULT_TYPE_TERMINAL_BUSY,
+ no_cause_result);
+ goto out;
+ }
+
+ stk->tx_buffer.data.array = g_try_malloc(oc->buf_size);
+ if (stk->tx_buffer.data.array == NULL) {
+ unsigned char no_cause_result[] = { 0x00 };
+
+ ADD_ERROR_RESULT(rsp.result, STK_RESULT_TYPE_TERMINAL_BUSY,
+ no_cause_result);
+ goto out;
+ }
+
+ stk->rx_buffer.data.len = oc->buf_size;
+ stk->rx_buffer.rx_remaining = 0;
+ stk->tx_buffer.data.len = oc->buf_size;
+ stk->tx_buffer.tx_avail = oc->buf_size;
+ stk->link_on_demand = (stk->pending_cmd->qualifier &
+ STK_OPEN_CHANNEL_FLAG_IMMEDIATE) ? FALSE : TRUE;
+
+ /*
+ * TODO
+ * Add a new primary PDP context based on the provided settings
+ * Send the Terminal Response or wait until the PDP context is activated
+ * in case of immediate link establishment not in background.
+ */
+out:
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&failure, stk);
+
+ if (rsp.result.type == STK_RESULT_TYPE_NOT_CAPABLE && stk->channel.id)
+ stk_close_channel(stk);
+}
+
+static void stk_send_data(struct ofono_stk *stk,
+ struct stk_common_byte_array data,
+ unsigned char qualifier)
+{
+ struct stk_response rsp;
+ struct ofono_error failure = { .type = OFONO_ERROR_TYPE_FAILURE };
+ unsigned int offset;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+
+ if (data.len > stk->tx_buffer.data.len ||
+ data.len > stk->tx_buffer.tx_avail) {
doc/coding-style.txt item M4
+ rsp.result.type = STK_RESULT_TYPE_BIP_ERROR;
+ goto out;
+ }
+
+ if (data.len) {
+ offset = stk->tx_buffer.data.len - stk->tx_buffer.tx_avail;
+ memcpy(stk->tx_buffer.data.array + offset, data.array,
+ data.len);
+
+ stk->tx_buffer.tx_avail -= data.len;
+
+ if (qualifier == STK_SEND_DATA_STORE_DATA) {
+ rsp.send_data.tx_avail = stk->tx_buffer.tx_avail;
+ goto out;
+ }
+ }
+
+ if (stk->channel.status == STK_CHANNEL_PACKET_DATA_SERVICE_NOT_ACTIVATED
+ && stk->link_on_demand == TRUE) {
+ /*
+ * TODO
+ * activate the context, update the channel status
+ * once the context is activated, send the data immediately
+ * and flush the tx buffer
+ */
+ } else {
+ /*
+ * TODO
+ * send the data immediately, flush the tx buffer
+ */
+ rsp.send_data.tx_avail = stk->tx_buffer.data.len;
+ }
+
+out:
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&failure, stk);
+}
+
+static void stk_receive_data(struct ofono_stk *stk, unsigned char data_len)
+{
+ struct stk_response rsp;
+ struct ofono_error failure = { .type = OFONO_ERROR_TYPE_FAILURE };
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+
+ if (stk->rx_buffer.rx_remaining == 0) {
+ rsp.result.type = STK_RESULT_TYPE_MISSING_INFO;
+ goto out;
+ }
+
+ if (data_len > stk->rx_buffer.rx_remaining) {
+ rsp.result.type = STK_RESULT_TYPE_MISSING_INFO;
+ data_len = stk->rx_buffer.rx_remaining;
+ }
+
+ if (data_len > CHANNEL_DATA_OBJECT_MAX_LENGTH)
+ data_len = CHANNEL_DATA_OBJECT_MAX_LENGTH;
+
+ rsp.receive_data.rx_data.array = stk->rx_buffer.data.array;
+ rsp.receive_data.rx_data.len = data_len;
+ stk->rx_buffer.rx_remaining -= data_len;
+ rsp.receive_data.rx_remaining = stk->rx_buffer.rx_remaining;
+
+out:
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&failure, stk);
+
+ if (rsp.receive_data.rx_data.len && stk->rx_buffer.rx_remaining > 0)
+ memmove(stk->rx_buffer.data.array, stk->rx_buffer.data.array +
+ data_len, stk->rx_buffer.rx_remaining);
+}
+
static int duration_to_msecs(const struct stk_duration *duration)
{
int msecs = duration->interval;
@@ -2589,6 +2774,220 @@ static gboolean handle_command_launch_browser(const struct
stk_command *cmd,
return FALSE;
}
+
+static void open_channel_cancel(struct ofono_stk *stk)
+{
+ /* TODO */
+}
+
+static void confirm_open_channel_cb(enum stk_agent_result result,
+ gboolean confirm,
+ void *user_data)
+{
+ struct ofono_stk *stk = user_data;
+
+ switch (result) {
+ case STK_AGENT_RESULT_TIMEOUT:
+ confirm = FALSE;
+ /* Fall through */
+
+ case STK_AGENT_RESULT_OK:
+ if (confirm)
+ break;
+
+ send_simple_response(stk, STK_RESULT_TYPE_USER_REJECT);
+ return;
+
+ case STK_AGENT_RESULT_TERMINATE:
+ default:
+ send_simple_response(stk, STK_RESULT_TYPE_USER_TERMINATED);
+ return;
+ }
+
+ stk_open_channel(stk);
+}
+
+static gboolean handle_command_open_channel(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(stk->atom);
+ const struct stk_command_open_channel *oc = &cmd->open_channel;
+ struct ofono_atom *gprs_atom;
+ int err;
+
+ /* Check first if channel is available */
+ if (stk->channel.id) {
+ unsigned char addnl_info[1];
+
+ addnl_info[0] = STK_RESULT_ADDNL_BIP_PB_NO_CHANNEL_AVAIL;
+ ADD_ERROR_RESULT(rsp->result, STK_RESULT_TYPE_BIP_ERROR,
+ addnl_info);
+ return TRUE;
+ }
+
+ gprs_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_GPRS);
+ if (gprs_atom == NULL || !__ofono_atom_get_registered(gprs_atom)) {
+ rsp->result.type = STK_RESULT_TYPE_NOT_CAPABLE;
+ return TRUE;
+ }
+
+ stk->gprs = __ofono_atom_get_data(gprs_atom);
+ stk->respond_on_exit = TRUE;
+ stk->cancel_cmd = open_channel_cancel;
+
+ /*
+ * Don't ask for user confirmation if AID is a null data object
+ * or is not provided
+ */
+ if (oc->alpha_id && strlen(oc->alpha_id) > 0) {
Calling strlen here is a bit overkill, you can always use
oc->alpha_id[0] != '\0'
+ char *alpha_id;
+
+ alpha_id = dbus_apply_text_attributes(oc->alpha_id,
+ &oc->text_attr);
+ if (alpha_id == NULL) {
+ rsp->result.type = STK_RESULT_TYPE_DATA_NOT_UNDERSTOOD;
+ return TRUE;
+ }
+
+ err = stk_agent_confirm_open_channel(stk->current_agent,
+ alpha_id,
+ &oc->icon_id,
+ confirm_open_channel_cb,
+ stk, NULL,
+ stk->timeout * 1000);
+ g_free(alpha_id);
+
+ if (err < 0) {
+ unsigned char no_cause_result[] = { 0x00 };
+
+ ADD_ERROR_RESULT(rsp->result,
+ STK_RESULT_TYPE_TERMINAL_BUSY,
+ no_cause_result);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ stk_open_channel(stk);
+
+ return FALSE;
+}
+
+static gboolean handle_command_close_channel(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ const struct stk_command_close_channel *cc = &cmd->close_channel;
+
+ /* Check if channel identifier is valid */
+ if (cmd->dst != (stk->channel.id | 0x20)) {
+ unsigned char addnl_info[1];
+
+ addnl_info[1] = STK_RESULT_ADDNL_BIP_PB_CHANNEL_ID_NOT_VALID;
+ ADD_ERROR_RESULT(rsp->result, STK_RESULT_TYPE_BIP_ERROR,
+ addnl_info);
+ return TRUE;
+ }
+
+ /*
+ * Don't inform the user about the link closing phase if AID is
+ * a null data object or is not provided
+ */
+ if (cc->alpha_id && strlen(cc->alpha_id) > 0)
+ stk_alpha_id_set(stk, cc->alpha_id, &cc->text_attr,
+ &cc->icon_id);
+
+ stk->respond_on_exit = TRUE;
+ stk->cancel_cmd = stk_request_cancel;
+
+ stk_close_channel(stk);
+
+ return FALSE;
+}
+
+static gboolean handle_command_receive_data(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ const struct stk_command_receive_data *rd = &cmd->receive_data;
+
+ /* Check if channel identifier is valid or already closed */
+ if (cmd->dst != (stk->channel.id | 0x20)) {
+ unsigned char addnl_info[1];
+
+ addnl_info[1] = STK_RESULT_ADDNL_BIP_PB_CHANNEL_ID_NOT_VALID;
+ ADD_ERROR_RESULT(rsp->result, STK_RESULT_TYPE_BIP_ERROR,
+ addnl_info);
+ return TRUE;
+ }
+
+ /*
+ * Don't inform the user during data transfer if AID is
+ * a null data object or is not provided
+ */
+ if (rd->alpha_id && strlen(rd->alpha_id) > 0)
+ stk_alpha_id_set(stk, rd->alpha_id, &rd->text_attr,
+ &rd->icon_id);
+
+ stk->respond_on_exit = TRUE;
+ stk->cancel_cmd = stk_request_cancel;
+
+ stk_receive_data(stk, rd->data_len);
+
+ return FALSE;
+}
+
+static gboolean handle_command_send_data(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ const struct stk_command_send_data *sd = &cmd->send_data;
+ unsigned char addnl_info[1];
+
+ /* Check if channel identifier is valid or already closed */
+ if (cmd->dst != (stk->channel.id | 0x20)) {
+ addnl_info[1] = STK_RESULT_ADDNL_BIP_PB_CHANNEL_ID_NOT_VALID;
+ ADD_ERROR_RESULT(rsp->result, STK_RESULT_TYPE_BIP_ERROR,
+ addnl_info);
+ return TRUE;
+ }
+
+ /* Check if the link was dropped */
+ if (stk->channel.status == STK_CHANNEL_LINK_DROPPED) {
+ addnl_info[1] = STK_RESULT_ADDNL_BIP_PB_CHANNEL_CLOSED;
+ ADD_ERROR_RESULT(rsp->result, STK_RESULT_TYPE_BIP_ERROR,
+ addnl_info);
+ return TRUE;
+ }
+
+ /*
+ * Don't inform the user during data transfer if AID is
+ * a null data object or is not provided
+ */
+ if (sd->alpha_id && strlen(sd->alpha_id) > 0)
+ stk_alpha_id_set(stk, sd->alpha_id, &sd->text_attr,
+ &sd->icon_id);
+
+ stk->respond_on_exit = TRUE;
+ stk->cancel_cmd = stk_request_cancel;
+
+ stk_send_data(stk, sd->data, cmd->qualifier);
+
+ return FALSE;
+}
+
+static gboolean handle_command_get_channel_status(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ rsp->result.type = STK_RESULT_TYPE_SUCCESS;
+ rsp->channel_status.channel.id = stk->channel.id;
+ rsp->channel_status.channel.status = stk->channel.status;
+ return TRUE;
+}
+
static void stk_proactive_command_cancel(struct ofono_stk *stk)
{
if (stk->immediate_response)
@@ -2782,6 +3181,31 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
&rsp, stk);
break;
+ case STK_COMMAND_TYPE_OPEN_CHANNEL:
+ respond = handle_command_open_channel(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
+ case STK_COMMAND_TYPE_CLOSE_CHANNEL:
+ respond = handle_command_close_channel(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
+ case STK_COMMAND_TYPE_RECEIVE_DATA:
+ respond = handle_command_receive_data(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
+ case STK_COMMAND_TYPE_SEND_DATA:
+ respond = handle_command_send_data(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
+ case STK_COMMAND_TYPE_GET_CHANNEL_STATUS:
+ respond = handle_command_get_channel_status(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
default:
rsp.result.type = STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD;
break;
Regards,
-Denis