summaryrefslogtreecommitdiffstats
path: root/drivers/isimodem/ussd.c
diff options
context:
space:
mode:
authorPekka Pessi <Pekka.Pessi@nokia.com>2010-09-16 20:32:49 +0300
committerDenis Kenzior <denkenz@gmail.com>2010-09-16 13:47:46 -0500
commitfe141909358bd4547210f5aab1ce02167e4c3c7c (patch)
tree646adef553014835dc88045ab7ca61b365024537 /drivers/isimodem/ussd.c
parent5e92604955cd7d6fc0cf4a5f3a7bb9f0000df209 (diff)
downloadofono-fe141909358bd4547210f5aab1ce02167e4c3c7c.tar.bz2
isimodem/ussd: fix mobile-terminated cases
ACK notifys. Handle mobile-terminated requests gracefully.
Diffstat (limited to 'drivers/isimodem/ussd.c')
-rw-r--r--drivers/isimodem/ussd.c130
1 files changed, 76 insertions, 54 deletions
diff --git a/drivers/isimodem/ussd.c b/drivers/isimodem/ussd.c
index 2f4091ce..94fe4d7b 100644
--- a/drivers/isimodem/ussd.c
+++ b/drivers/isimodem/ussd.c
@@ -1,7 +1,7 @@
/*
* This file is part of oFono - Open Source Telephony
*
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Contact: Aki Niemi <aki.niemi@nokia.com>
*
@@ -50,41 +50,84 @@
struct ussd_data {
GIsiClient *client;
+ int mt_session;
};
-static inline int isi_type_to_status(uint8_t type)
+static void ussd_notify_ack(struct ussd_data *ud)
{
+ const unsigned char msg[] = {
+ SS_GSM_USSD_SEND_REQ,
+ SS_GSM_USSD_NOTIFY,
+ 0x00 /* subblock count */
+ };
+
+ g_isi_send(ud->client, msg, sizeof(msg), SS_TIMEOUT, NULL, NULL, NULL);
+}
+
+static void ussd_ind_cb(GIsiClient *client,
+ const void *restrict data, size_t len,
+ uint16_t object, void *opaque)
+{
+ const unsigned char *msg = data;
+ struct ofono_ussd *ussd = opaque;
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ int dcs;
+ int type;
+ size_t ussdlen;
+ int status;
+
+ if (!msg || len < 4 || msg[0] != SS_GSM_USSD_RECEIVE_IND)
+ return;
+
+ dcs = msg[1];
+ type = msg[2];
+ ussdlen = msg[3];
+
+ if (len < 4 + ussdlen)
+ ussdlen = len - 4;
+
switch (type) {
+ case 0:
+ /* Nothing - this is response to NOTIFY_ACK REQ */
+ return;
+
case SS_GSM_USSD_MT_REPLY:
- return OFONO_USSD_STATUS_LOCAL_CLIENT_RESPONDED;
+ /* This never happens, but.. */
+ status = OFONO_USSD_STATUS_LOCAL_CLIENT_RESPONDED;
+ break;
+
case SS_GSM_USSD_COMMAND:
- return OFONO_USSD_STATUS_ACTION_REQUIRED;
+ if (ud->mt_session)
+ /* Ignore, we get SS_GSM_USSD_REQUEST, too */
+ return;
+ status = OFONO_USSD_STATUS_ACTION_REQUIRED;
+ break;
+
case SS_GSM_USSD_NOTIFY:
- return OFONO_USSD_STATUS_NOTIFY;
+ status = OFONO_USSD_STATUS_NOTIFY;
+ ussd_notify_ack(ud);
+ break;
+
case SS_GSM_USSD_END:
- return OFONO_USSD_STATUS_TERMINATED;
+ status = OFONO_USSD_STATUS_TERMINATED;
+ ud->mt_session = 0;
+ break;
+
case SS_GSM_USSD_REQUEST:
+ ud->mt_session = 1;
+ status = OFONO_USSD_STATUS_ACTION_REQUIRED;
+ break;
+
default:
- return OFONO_USSD_STATUS_NOT_SUPPORTED;
+ status = OFONO_USSD_STATUS_NOT_SUPPORTED;
}
-}
-
-static void ussd_parse(struct ofono_ussd *ussd, const void *restrict data,
- size_t len)
-{
- const unsigned char *msg = data;
- int status = OFONO_USSD_STATUS_NOT_SUPPORTED;
- if (!msg || len < 4)
- ofono_ussd_notify(ussd, status, 0, NULL, 0);
+ DBG("type: %u %s, dcs: 0x%02x, len: %u",
+ type, ss_ussd_type_name(type), dcs, ussdlen);
- status = isi_type_to_status(msg[2]);
-
- if (msg[3] == 0 || (size_t)(msg[3] + 4) > len)
- ofono_ussd_notify(ussd, status, msg[1], msg + 4, msg[3]);
+ ofono_ussd_notify(ussd, status, dcs, msg + 4, ussdlen);
}
-
static gboolean ussd_send_resp_cb(GIsiClient *client,
const void *restrict data, size_t len,
uint16_t object, void *opaque)
@@ -104,12 +147,11 @@ static gboolean ussd_send_resp_cb(GIsiClient *client,
if (msg[0] == SS_SERVICE_FAILED_RESP)
goto error;
- if (len < 4 || msg[0] != SS_GSM_USSD_SEND_RESP)
+ if (msg[0] != SS_GSM_USSD_SEND_RESP)
return FALSE;
CALLBACK_WITH_SUCCESS(cb, cbd->data);
- ussd_parse(cbd->user, data, len);
return TRUE;
error:
@@ -118,13 +160,17 @@ error:
}
-static GIsiRequest *ussd_send(GIsiClient *client,
- int dcs, uint8_t const *str, size_t len,
- void *data, GDestroyNotify notify)
+static void isi_request(struct ofono_ussd *ussd, int dcs,
+ const unsigned char *pdu, int len,
+ ofono_ussd_cb_t cb, void *data)
{
+ 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[] = {
SS_GSM_USSD_SEND_REQ,
- SS_GSM_USSD_COMMAND,
+ ud->mt_session
+ ? SS_GSM_USSD_MT_REPLY
+ : SS_GSM_USSD_COMMAND,
0x01, /* subblock count */
SS_GSM_USSD_STRING,
4 + len + 3, /* subblock length */
@@ -132,27 +178,16 @@ static GIsiRequest *ussd_send(GIsiClient *client,
len, /* string length */
/* USSD string goes here */
};
-
const struct iovec iov[2] = {
{ (uint8_t *)msg, sizeof(msg) },
- { (uint8_t *)str, len }
+ { (uint8_t *)pdu, len }
};
- return g_isi_vsend(client, iov, 2, SS_TIMEOUT,
- ussd_send_resp_cb, data, notify);
-}
-
-static void isi_request(struct ofono_ussd *ussd, int dcs,
- const unsigned char *pdu, int len,
- ofono_ussd_cb_t cb, void *data)
-{
- struct ussd_data *ud = ofono_ussd_get_data(ussd);
- struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
-
if (!cbd)
goto error;
- if (ussd_send(ud->client, dcs, pdu, len, cbd, g_free))
+ if (g_isi_vsend(ud->client, iov, 2, SS_TIMEOUT,
+ ussd_send_resp_cb, cbd, g_free))
return;
error:
@@ -184,19 +219,6 @@ error:
g_free(cbd);
}
-static void ussd_ind_cb(GIsiClient *client,
- const void *restrict data, size_t len,
- uint16_t object, void *opaque)
-{
- const unsigned char *msg = data;
- struct ofono_ussd *ussd = opaque;
-
- if (!msg || len < 4 || msg[0] != SS_GSM_USSD_RECEIVE_IND)
- return;
-
- ussd_parse(ussd, data, len);
-}
-
static gboolean isi_ussd_register(gpointer user)
{
struct ofono_ussd *ussd = user;