Open Source Telephony
 help / color / mirror / Atom feed
* [PATCH v3 1/4] Add macro for general result and additional info
@ 2010-10-18  8:00 Yang Gu
  2010-10-18  8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Yang Gu @ 2010-10-18  8:00 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1609 bytes --]

---
 src/stkutil.h |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/src/stkutil.h b/src/stkutil.h
index 2d98185..5c75524 100644
--- a/src/stkutil.h
+++ b/src/stkutil.h
@@ -254,6 +254,8 @@ enum stk_result_type {
 	STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD =	0x31,
 	STK_RESULT_TYPE_DATA_NOT_UNDERSTOOD =		0x32,
 	STK_RESULT_TYPE_COMMAND_ID_UNKNOWN =		0x33,
+	STK_RESULT_TYPE_SS_RETURN_ERROR =		0x34,
+	STK_RESULT_TYPE_SMS_RP_ERROR =			0x35,
 	STK_RESULT_TYPE_MINIMUM_NOT_MET =		0x36,
 	STK_RESULT_TYPE_USSD_RETURN_ERROR =		0x37,
 	STK_RESULT_TYPE_CALL_CONTROL_PERMANENT =	0x39,
@@ -263,6 +265,26 @@ enum stk_result_type {
 	STK_RESULT_TYPE_MMS_ERROR =			0x3D,
 };
 
+/* Defined according to TS 102.223 Section 8.12.2 */
+enum stk_result_addnl_me_pb {
+	STK_RESULT_ADDNL_ME_PB_NO_SPECIFIC_CAUSE =	0x00,
+	STK_RESULT_ADDNL_ME_PB_SCREEN_BUSY =		0x01,
+	STK_RESULT_ADDNL_ME_PB_BUSY_ON_CALL =		0x02,
+	STK_RESULT_ADDNL_ME_PB_SS_BUSY =		0x03,
+	STK_RESULT_ADDNL_ME_PB_NO_SERVICE =		0x04,
+	STK_RESULT_ADDNL_ME_PB_NO_ACCESS =		0x05,
+	STK_RESULT_ADDNL_ME_PB_NO_RADIO_RESOURCE =	0x06,
+	STK_RESULT_ADDNL_ME_PB_NOT_IN_SPEECH_CALL =	0x07,
+	STK_RESULT_ADDNL_ME_PB_USSD_BUSY =		0x08,
+	STK_RESULT_ADDNL_ME_PB_BUSY_ON_SEND_DTMF =	0x09,
+	STK_RESULT_ADDNL_ME_PB_NO_NAA_ACTIVE =		0x0A
+};
+
+/* Defined according to TS 31.111 Section 8.12.4 */
+enum stk_result_addnl_ss_pb {
+	STK_RESULT_ADDNL_SS_PB_NO_SPECIFIC_CAUSE =	0x00
+};
+
 enum stk_tone_type {
 	STK_TONE_TYPE_DIAL_TONE =	0x01,
 	STK_TONE_TYPE_BUSY_TONE =	0x02,
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v3 2/4] stk: Support send ss response
  2010-10-18  8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
@ 2010-10-18  8:00 ` Yang Gu
  2010-10-20 23:22   ` Denis Kenzior
  2010-10-18  8:00 ` [PATCH v3 3/4] ss: Use errno for ssc handling functions Yang Gu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Yang Gu @ 2010-10-18  8:00 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 524 bytes --]

---
 src/stkutil.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/src/stkutil.c b/src/stkutil.c
index 82da079..cdd66bd 100644
--- a/src/stkutil.c
+++ b/src/stkutil.c
@@ -5455,6 +5455,8 @@ const unsigned char *stk_pdu_from_response(const struct stk_response *response,
 					&response->select_item.item_id,
 					NULL);
 		break;
+	case STK_COMMAND_TYPE_SEND_SS:
+		break;
 	case STK_COMMAND_TYPE_SETUP_CALL:
 		ok = build_setup_call(&builder, response);
 		break;
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v3 3/4] ss: Use errno for ssc handling functions
  2010-10-18  8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
  2010-10-18  8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
@ 2010-10-18  8:00 ` Yang Gu
  2010-10-18  8:00 ` [PATCH v3 4/4] cf: Handle send ss proactive command Yang Gu
  2010-10-20 23:22 ` [PATCH v3 1/4] Add macro for general result and additional info Denis Kenzior
  3 siblings, 0 replies; 6+ messages in thread
From: Yang Gu @ 2010-10-18  8:00 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 13857 bytes --]

---
 src/call-barring.c    |   63 ++++++++++++++----------------------------------
 src/call-forwarding.c |   63 +++++++++++++++++-------------------------------
 src/call-settings.c   |   34 ++++++++------------------
 src/ussd.c            |   55 ++++++++++++++++++++++++++++--------------
 4 files changed, 88 insertions(+), 127 deletions(-)

diff --git a/src/call-barring.c b/src/call-barring.c
index f89602e..04d9bab 100644
--- a/src/call-barring.c
+++ b/src/call-barring.c
@@ -359,25 +359,19 @@ static const char *cb_ss_service_to_fac(const char *svc)
 	return NULL;
 }
 
-static gboolean cb_ss_control(int type, const char *sc,
+static int cb_ss_control(int type, const char *sc,
 				const char *sia, const char *sib,
 				const char *sic, const char *dn,
 				DBusMessage *msg, void *data)
 {
 	struct ofono_call_barring *cb = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
 	int cls = BEARER_CLASS_DEFAULT;
 	const char *fac;
-	DBusMessage *reply;
 	void *operation = NULL;
 	int i;
 
-	if (__ofono_call_barring_is_busy(cb)) {
-		reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (__ofono_call_barring_is_busy(cb))
+		return -EBUSY;
 
 	DBG("Received call barring ss control request");
 
@@ -386,7 +380,7 @@ static gboolean cb_ss_control(int type, const char *sc,
 
 	fac = cb_ss_service_to_fac(sc);
 	if (!fac)
-		return FALSE;
+		return -ENOENT;
 
 	cb_set_query_bounds(cb, fac, type == SS_CONTROL_TYPE_QUERY);
 
@@ -397,13 +391,13 @@ static gboolean cb_ss_control(int type, const char *sc,
 	cb->ss_req_lock = i;
 
 	if (strlen(sic) > 0)
-		goto bad_format;
+		return -EINVAL;
 
 	if (strlen(dn) > 0)
-		goto bad_format;
+		return -EINVAL;
 
 	if (type != SS_CONTROL_TYPE_QUERY && !is_valid_pin(sia, PIN_TYPE_NET))
-		goto bad_format;
+		return -EINVAL;
 
 	switch (type) {
 	case SS_CONTROL_TYPE_ACTIVATION:
@@ -419,12 +413,8 @@ static gboolean cb_ss_control(int type, const char *sc,
 		break;
 	}
 
-	if (!operation) {
-		reply = __ofono_error_not_implemented(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (!operation)
+		return -ENOSYS;
 
 	/*
 	 * According to 27.007, AG, AC and AB only work with mode = 0
@@ -434,7 +424,7 @@ static gboolean cb_ss_control(int type, const char *sc,
 	if ((!strcmp(fac, "AG") || !strcmp(fac, "AC") || !strcmp(fac, "AB")) &&
 		(type == SS_CONTROL_TYPE_ACTIVATION ||
 			type == SS_CONTROL_TYPE_REGISTRATION))
-		goto bad_format;
+		return -EINVAL;
 
 	if (strlen(sib) > 0) {
 		long service_code;
@@ -443,12 +433,12 @@ static gboolean cb_ss_control(int type, const char *sc,
 		service_code = strtoul(sib, &end, 10);
 
 		if (end == sib || *end != '\0')
-			goto bad_format;
+			return -EINVAL;
 
 		cls = mmi_service_code_to_bearer_class(service_code);
 
 		if (cls == 0)
-			goto bad_format;
+			return -EINVAL;
 	}
 
 	cb->ss_req_cls = cls;
@@ -473,12 +463,7 @@ static gboolean cb_ss_control(int type, const char *sc,
 		break;
 	}
 
-	return TRUE;
-
-bad_format:
-	reply = __ofono_error_invalid_format(msg);
-	g_dbus_send_message(conn, reply);
-	return TRUE;
+	return 0;
 }
 
 static void cb_set_passwd_callback(const struct ofono_error *error, void *data)
@@ -496,21 +481,15 @@ static void cb_set_passwd_callback(const struct ofono_error *error, void *data)
 	__ofono_dbus_pending_reply(&cb->pending, reply);
 }
 
-static gboolean cb_ss_passwd(const char *sc,
+static int cb_ss_passwd(const char *sc,
 				const char *old, const char *new,
 				DBusMessage *msg, void *data)
 {
 	struct ofono_call_barring *cb = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
-	DBusMessage *reply;
 	const char *fac;
 
-	if (__ofono_call_barring_is_busy(cb)) {
-		reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (__ofono_call_barring_is_busy(cb))
+		return -EBUSY;
 
 	DBG("Received call barring ss password change request");
 
@@ -522,19 +501,15 @@ static gboolean cb_ss_passwd(const char *sc,
 		fac = cb_ss_service_to_fac(sc);
 
 	if (!fac)
-		return FALSE;
+		return -ENOENT;
 
 	if (!is_valid_pin(old, PIN_TYPE_NET) || !is_valid_pin(new, PIN_TYPE_NET))
-		goto bad_format;
+		return -EINVAL;
 
 	cb->pending = dbus_message_ref(msg);
 	cb->driver->set_passwd(cb, fac, old, new, cb_set_passwd_callback, cb);
 
-	return TRUE;
-bad_format:
-	reply = __ofono_error_invalid_format(msg);
-	g_dbus_send_message(conn, reply);
-	return TRUE;
+	return 0;
 }
 
 static void cb_register_ss_controls(struct ofono_call_barring *cb)
diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index 928cda1..fd05d38 100644
--- a/src/call-forwarding.c
+++ b/src/call-forwarding.c
@@ -883,30 +883,24 @@ static void cf_ss_control_callback(const struct ofono_error *error, void *data)
 	ss_set_query_next_cf_cond(cf);
 }
 
-static gboolean cf_ss_control(int type, const char *sc,
+static int cf_ss_control(int type, const char *sc,
 				const char *sia, const char *sib,
 				const char *sic, const char *dn,
 				DBusMessage *msg, void *data)
 {
 	struct ofono_call_forwarding *cf = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
 	int cls = BEARER_CLASS_SS_DEFAULT;
 	int timeout = DEFAULT_NO_REPLY_TIMEOUT;
 	int cf_type;
-	DBusMessage *reply;
 	struct ofono_phone_number ph;
 	void *operation = NULL;
 
 	/* Before we do anything, make sure we're actually initialized */
 	if (!cf)
-		return FALSE;
-
-	if (__ofono_call_forwarding_is_busy(cf)) {
-		reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
+		return -ENOENT;
 
-		return TRUE;
-	}
+	if (__ofono_call_forwarding_is_busy(cf))
+		return -EBUSY;
 
 	DBG("Received call forwarding ss control request");
 
@@ -926,13 +920,13 @@ static gboolean cf_ss_control(int type, const char *sc,
 	else if (!strcmp(sc, "004"))
 		cf_type = CALL_FORWARDING_TYPE_ALL_CONDITIONAL;
 	else
-		return FALSE;
+		return -ENOENT;
 
 	if (strlen(sia) &&
-		(type == SS_CONTROL_TYPE_QUERY ||
-		type == SS_CONTROL_TYPE_ERASURE ||
-		type == SS_CONTROL_TYPE_DEACTIVATION))
-		goto error;
+			(type == SS_CONTROL_TYPE_QUERY ||
+			type == SS_CONTROL_TYPE_ERASURE ||
+			type == SS_CONTROL_TYPE_DEACTIVATION))
+		return -EINVAL;
 
 	/*
 	 * Activation / Registration is figured context specific according to
@@ -944,8 +938,8 @@ static gboolean cf_ss_control(int type, const char *sc,
 		type = SS_CONTROL_TYPE_REGISTRATION;
 
 	if (type == SS_CONTROL_TYPE_REGISTRATION &&
-		!valid_phone_number_format(sia))
-		goto error;
+			!valid_phone_number_format(sia))
+		return -EINVAL;
 
 	if (strlen(sib) > 0) {
 		long service_code;
@@ -954,32 +948,32 @@ static gboolean cf_ss_control(int type, const char *sc,
 		service_code = strtoul(sib, &end, 10);
 
 		if (end == sib || *end != '\0')
-			goto error;
+			return -EINVAL;
 
 		cls = mmi_service_code_to_bearer_class(service_code);
 
 		if (cls == 0)
-			goto error;
+			return -EINVAL;
 	}
 
 	if (strlen(sic) > 0) {
 		char *end;
 
 		if  (type != SS_CONTROL_TYPE_REGISTRATION)
-			goto error;
+			return -EINVAL;
 
 		if (cf_type != CALL_FORWARDING_TYPE_ALL &&
 			cf_type != CALL_FORWARDING_TYPE_ALL_CONDITIONAL &&
 			cf_type != CALL_FORWARDING_TYPE_NO_REPLY)
-			goto error;
+			return -EINVAL;
 
 		timeout = strtoul(sic, &end, 10);
 
 		if (end == sic || *end != '\0')
-			goto error;
+			return -EINVAL;
 
 		if (timeout < 1 || timeout > 30)
-			goto error;
+			return -EINVAL;
 	}
 
 	switch (type) {
@@ -1000,21 +994,13 @@ static gboolean cf_ss_control(int type, const char *sc,
 		break;
 	}
 
-	if (!operation) {
-		reply = __ofono_error_not_implemented(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (!operation)
+		return -ENOSYS;
 
 	cf->ss_req = g_try_new0(struct cf_ss_request, 1);
 
-	if (!cf->ss_req) {
-		reply = __ofono_error_failed(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (!cf->ss_req)
+		return -ENOMEM;
 
 	cf->ss_req->ss_type = type;
 	cf->ss_req->cf_type = cf_type;
@@ -1070,12 +1056,7 @@ static gboolean cf_ss_control(int type, const char *sc,
 		break;
 	}
 
-	return TRUE;
-
-error:
-	reply = __ofono_error_invalid_format(msg);
-	g_dbus_send_message(conn, reply);
-	return TRUE;
+	return 0;
 }
 
 static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
diff --git a/src/call-settings.c b/src/call-settings.c
index 23da47e..4f4812e 100644
--- a/src/call-settings.c
+++ b/src/call-settings.c
@@ -402,35 +402,29 @@ static void cw_ss_set_callback(const struct ofono_error *error, void *data)
 				cw_ss_query_callback, cs);
 }
 
-static gboolean cw_ss_control(int type,
+static int cw_ss_control(int type,
 				const char *sc, const char *sia,
 				const char *sib, const char *sic,
 				const char *dn, DBusMessage *msg, void *data)
 {
 	struct ofono_call_settings *cs = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
 	int cls = BEARER_CLASS_SS_DEFAULT;
-	DBusMessage *reply;
 
 	if (!cs)
-		return FALSE;
+		return -ENOENT;
 
 	if (strcmp(sc, "43"))
-		return FALSE;
+		return -ENOENT;
 
-	if (__ofono_call_settings_is_busy(cs)) {
-		reply = __ofono_error_busy(msg);
-		goto error;
-	}
+	if (__ofono_call_settings_is_busy(cs))
+		return -EBUSY;
 
 	if (strlen(sib) || strlen(sib) || strlen(dn))
-		goto bad_format;
+		return -EINVAL;
 
 	if ((type == SS_CONTROL_TYPE_QUERY && !cs->driver->cw_query) ||
-		(type != SS_CONTROL_TYPE_QUERY && !cs->driver->cw_set)) {
-		reply = __ofono_error_not_implemented(msg);
-		goto error;
-	}
+			(type != SS_CONTROL_TYPE_QUERY && !cs->driver->cw_set))
+		return -ENOSYS;
 
 	if (strlen(sia) > 0) {
 		long service_code;
@@ -439,11 +433,11 @@ static gboolean cw_ss_control(int type,
 		service_code = strtoul(sia, &end, 10);
 
 		if (end == sia || *end != '\0')
-			goto bad_format;
+			return -EINVAL;
 
 		cls = mmi_service_code_to_bearer_class(service_code);
 		if (cls == 0)
-			goto bad_format;
+			return -EINVAL;
 	}
 
 	cs->ss_req_cls = cls;
@@ -478,13 +472,7 @@ static gboolean cw_ss_control(int type,
 		break;
 	}
 
-	return TRUE;
-
-bad_format:
-	reply = __ofono_error_invalid_format(msg);
-error:
-	g_dbus_send_message(conn, reply);
-	return TRUE;
+	return 0;
 }
 
 static void generate_ss_query_reply(struct ofono_call_settings *cs,
diff --git a/src/ussd.c b/src/ussd.c
index 59e0a49..c0b7af8 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -205,32 +205,29 @@ static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
 		break;
 
 	default:
-		return FALSE;
+		return -ENOENT;
 	}
 
 	if (strcmp(sc, "03") || strlen(dn))
-		return FALSE;
+		return -ENOENT;
 
 	/* If SIC & SID don't match, then we just bail out here */
-	if (strcmp(sic, sid)) {
-		DBusConnection *conn = ofono_dbus_get_connection();
-		DBusMessage *reply = __ofono_error_invalid_format(msg);
-		g_dbus_send_message(conn, reply);
-		return TRUE;
-	}
+	if (strcmp(sic, sid))
+		return -EINVAL;
 
 	while ((l = g_slist_find_custom(l, sia,
 			ssc_entry_find_by_service)) != NULL) {
 		struct ssc_entry *entry = l->data;
 		ofono_ussd_passwd_cb_t cb = entry->cb;
+		int result = cb(sia, sib, sic, msg, entry->user);
 
-		if (cb(sia, sib, sic, msg, entry->user))
-			return TRUE;
+		if (result != -ENOENT)
+			return result;
 
 		l = l->next;
 	}
 
-	return FALSE;
+	return -ENOENT;
 }
 
 static gboolean recognized_control_string(struct ofono_ussd *ussd,
@@ -240,7 +237,8 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
 	char *str = g_strdup(ss_str);
 	char *sc, *sia, *sib, *sic, *sid, *dn;
 	int type;
-	gboolean ret = FALSE;
+	int ret = -ENOENT;
+	int result;
 
 	DBG("parsing control string");
 
@@ -256,9 +254,10 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
 		 * because it uses a fourth SI and is thus not a valid
 		 * control string.
 		 */
-		if (recognized_passwd_change_string(ussd, type, sc,
-					sia, sib, sic, sid, dn, msg)) {
-			ret = TRUE;
+		result = recognized_passwd_change_string(ussd, type, sc,
+						sia, sib, sic, sid, dn, msg);
+		if (result != -ENOENT) {
+			ret = result;
 			goto out;
 		}
 
@@ -270,8 +269,11 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
 			struct ssc_entry *entry = l->data;
 			ofono_ussd_ssc_cb_t cb = entry->cb;
 
-			if (cb(type, sc, sia, sib, sic, dn, msg, entry->user)) {
-				ret = TRUE;
+			result = cb(type, sc, sia, sib, sic, dn, msg,
+								entry->user);
+
+			if (result != -ENOENT) {
+				ret = result;
 				goto out;
 			}
 
@@ -552,6 +554,7 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
 	int dcs = 0x0f;
 	unsigned char buf[160];
 	long num_packed;
+	int result;
 
 	if (__ofono_ussd_is_busy(ussd))
 		return __ofono_error_busy(msg);
@@ -564,8 +567,22 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
 		return __ofono_error_invalid_format(msg);
 
 	DBG("checking if this is a recognized control string");
-	if (recognized_control_string(ussd, str, msg))
-		return NULL;
+
+	result = recognized_control_string(ussd, str, msg);
+	if (result != -ENOENT) {
+		switch (result) {
+		case -EBUSY:
+			return __ofono_error_busy(msg);
+		case -EINVAL:
+			return __ofono_error_invalid_format(msg);
+		case -ENOSYS:
+			return __ofono_error_not_implemented(msg);
+		case -ENOMEM:
+			return __ofono_error_failed(msg);
+		default:
+			return NULL;
+		}
+	}
 
 	vca = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_VOICECALL);
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v3 4/4] cf: Handle send ss proactive command
  2010-10-18  8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
  2010-10-18  8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
  2010-10-18  8:00 ` [PATCH v3 3/4] ss: Use errno for ssc handling functions Yang Gu
@ 2010-10-18  8:00 ` Yang Gu
  2010-10-20 23:22 ` [PATCH v3 1/4] Add macro for general result and additional info Denis Kenzior
  3 siblings, 0 replies; 6+ messages in thread
From: Yang Gu @ 2010-10-18  8:00 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 22986 bytes --]

---
 src/call-forwarding.c |  262 +++++++++++++++++++++++++++++++++++++++++++++---
 src/ofono.h           |   28 +++++
 src/stk.c             |  130 ++++++++++++++++++++++++
 src/ussd.c            |  145 +++++++++++++++++++++++++++
 4 files changed, 548 insertions(+), 17 deletions(-)

diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index fd05d38..9384bff 100644
--- a/src/call-forwarding.c
+++ b/src/call-forwarding.c
@@ -55,11 +55,14 @@ struct ofono_call_forwarding {
 	GSList *cf_conditions[4];
 	int flags;
 	DBusMessage *pending;
+	struct ofono_ss_request *req;
 	int query_next;
 	int query_end;
 	struct cf_ss_request *ss_req;
 	struct ofono_ussd *ussd;
+	struct ofono_stk *stk;
 	unsigned int ussd_watch;
+	unsigned int stk_watch;
 	const struct ofono_call_forwarding_driver *driver;
 	void *driver_data;
 	struct ofono_atom *atom;
@@ -68,6 +71,7 @@ struct ofono_call_forwarding {
 static void get_query_next_cf_cond(struct ofono_call_forwarding *cf);
 static void set_query_next_cf_cond(struct ofono_call_forwarding *cf);
 static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf);
+static void ss_set_query_next_cf_cond_stk(struct ofono_call_forwarding *cf);
 static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf);
 
 struct cf_ss_request {
@@ -77,6 +81,27 @@ struct cf_ss_request {
 	GSList *cf_list[4];
 };
 
+static void request_finish_stk(struct ofono_call_forwarding *cf,
+					const struct ofono_error *error)
+{
+	struct ofono_ss_request *req = cf->req;
+
+	if (req && req->cb)
+		req->cb(error, req->user_data);
+
+	cf->req = NULL;
+}
+
+static void request_cancel_stk(void *ss)
+{
+	struct ofono_call_forwarding *cf = ss;
+
+	if (!cf->req || !cf->req->cb)
+		return;
+
+	cf->req = NULL;
+}
+
 static gint cf_condition_compare(gconstpointer a, gconstpointer b)
 {
 	const struct ofono_call_forwarding_condition *ca = a;
@@ -860,12 +885,52 @@ static void ss_set_query_cf_callback(const struct ofono_error *error, int total,
 	}
 }
 
+static void ss_set_query_cf_cb_stk(const struct ofono_error *error, int total,
+			const struct ofono_call_forwarding_condition *list,
+			void *data)
+{
+	struct ofono_call_forwarding *cf = data;
+	GSList *l;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		ofono_error("Setting succeeded, but query failed");
+		cf->flags &= ~CALL_FORWARDING_FLAG_CACHED;
+		request_finish_stk(cf, error);
+		return;
+	}
+
+	l = cf_cond_list_create(total, list);
+	DBG("%s conditions:", cf_type_lut[cf->query_next]);
+	cf_cond_list_print(l);
+
+	cf->ss_req->cf_list[cf->query_next] = l;
+
+	if (cf->query_next == cf->query_end) {
+		request_finish_stk(cf, error);
+		g_free(cf->ss_req);
+		cf->ss_req = NULL;
+	}
+
+	set_new_cond_list(cf, cf->query_next, l);
+
+	if (cf->query_next != cf->query_end) {
+		cf->query_next++;
+		ss_set_query_next_cf_cond_stk(cf);
+	}
+}
+
 static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf)
 {
 	cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
 			ss_set_query_cf_callback, cf);
 }
 
+static void ss_set_query_next_cf_cond_stk(struct ofono_call_forwarding *cf)
+{
+	cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
+			ss_set_query_cf_cb_stk, cf);
+}
+
 static void cf_ss_control_callback(const struct ofono_error *error, void *data)
 {
 	struct ofono_call_forwarding *cf = data;
@@ -883,16 +948,31 @@ static void cf_ss_control_callback(const struct ofono_error *error, void *data)
 	ss_set_query_next_cf_cond(cf);
 }
 
-static int cf_ss_control(int type, const char *sc,
-				const char *sia, const char *sib,
-				const char *sic, const char *dn,
-				DBusMessage *msg, void *data)
+static void cf_ss_control_cb_stk(const struct ofono_error *error, void *data)
 {
 	struct ofono_call_forwarding *cf = data;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		DBG("Error occurred during cf ss control set/erasure");
+
+		request_finish_stk(cf, error);
+
+		g_free(cf->ss_req);
+		cf->ss_req = NULL;
+		return;
+	}
+
+	ss_set_query_next_cf_cond_stk(cf);
+}
+
+static int parse_ss_control(struct ofono_call_forwarding *cf, int type,
+				const char *sc, const char *sia,
+				const char *sib, const char *sic,
+				const char *dn)
+{
 	int cls = BEARER_CLASS_SS_DEFAULT;
 	int timeout = DEFAULT_NO_REPLY_TIMEOUT;
 	int cf_type;
-	struct ofono_phone_number ph;
 	void *operation = NULL;
 
 	/* Before we do anything, make sure we're actually initialized */
@@ -1004,9 +1084,18 @@ static int cf_ss_control(int type, const char *sc,
 
 	cf->ss_req->ss_type = type;
 	cf->ss_req->cf_type = cf_type;
-	cf->ss_req->cls = cls;
 
-	cf->pending = dbus_message_ref(msg);
+	/*
+	 * Some modems don't understand all classes very well, particularly
+	 * the older models.  So if the bearer class is the default, we
+	 * just use the more commonly understood value of 7 since BEARER_SMS
+	 * is not applicable to CallForwarding conditions according to 22.004
+	 * Annex A
+	 */
+	if (cls == BEARER_CLASS_SS_DEFAULT)
+		cls = BEARER_CLASS_DEFAULT;
+
+	cf->ss_req->cls = cls;
 
 	switch (cf->ss_req->cf_type) {
 	case CALL_FORWARDING_TYPE_ALL:
@@ -1023,15 +1112,34 @@ static int cf_ss_control(int type, const char *sc,
 		break;
 	}
 
-	/*
-	 * Some modems don't understand all classes very well, particularly
-	 * the older models.  So if the bearer class is the default, we
-	 * just use the more commonly understood value of 7 since BEARER_SMS
-	 * is not applicable to CallForwarding conditions according to 22.004
-	 * Annex A
-	 */
-	if (cls == BEARER_CLASS_SS_DEFAULT)
-		cls = BEARER_CLASS_DEFAULT;
+	return 0;
+}
+
+static int cf_ss_control(int type, const char *sc,
+				const char *sia, const char *sib,
+				const char *sic, const char *dn,
+				DBusMessage *msg, void *data)
+{
+	struct ofono_call_forwarding *cf = data;
+	int ret;
+	char *end;
+	int timeout;
+	int cls;
+	int cf_type;
+	struct ofono_phone_number ph;
+
+	ret = parse_ss_control(cf, type, sc, sia, sib, sic, dn);
+	if (ret != 0)
+		return ret;
+
+	cls = cf->ss_req->cls;
+	cf_type = cf->ss_req->cf_type;
+
+	timeout = DEFAULT_NO_REPLY_TIMEOUT;
+	if (strlen(sic) > 0)
+		timeout = strtoul(sic, &end, 10);
+
+	cf->pending = dbus_message_ref(msg);
 
 	switch (cf->ss_req->ss_type) {
 	case SS_CONTROL_TYPE_REGISTRATION:
@@ -1059,6 +1167,60 @@ static int cf_ss_control(int type, const char *sc,
 	return 0;
 }
 
+static int cf_ss_control_stk(int type, const char *sc,
+				const char *sia, const char *sib,
+				const char *sic, const char *dn,
+				struct ofono_ss_request *req, void *data)
+{
+	struct ofono_call_forwarding *cf = data;
+	int ret;
+	char *end;
+	int timeout;
+	int cls;
+	int cf_type;
+	struct ofono_phone_number ph;
+
+	ret = parse_ss_control(cf, type, sc, sia, sib, sic, dn);
+	if (ret != 0)
+		return ret;
+
+	cls = cf->ss_req->cls;
+	cf_type = cf->ss_req->cf_type;
+
+	timeout = DEFAULT_NO_REPLY_TIMEOUT;
+	if (strlen(sic) > 0)
+		timeout = strtoul(sic, &end, 10);
+
+	cf->req = req;
+	cf->req->cancel = request_cancel_stk;
+	cf->req->ss = cf;
+
+	switch (cf->ss_req->ss_type) {
+	case SS_CONTROL_TYPE_REGISTRATION:
+		string_to_phone_number(sia, &ph);
+		cf->driver->registration(cf, cf_type, cls, &ph, timeout,
+					cf_ss_control_cb_stk, cf);
+		break;
+	case SS_CONTROL_TYPE_ACTIVATION:
+		cf->driver->activation(cf, cf_type, cls, cf_ss_control_cb_stk,
+					cf);
+		break;
+	case SS_CONTROL_TYPE_DEACTIVATION:
+		cf->driver->deactivation(cf, cf_type, cls,
+					cf_ss_control_cb_stk, cf);
+		break;
+	case SS_CONTROL_TYPE_ERASURE:
+		cf->driver->erasure(cf, cf_type, cls, cf_ss_control_cb_stk,
+					cf);
+		break;
+	case SS_CONTROL_TYPE_QUERY:
+		ss_set_query_next_cf_cond_stk(cf);
+		break;
+	}
+
+	return 0;
+}
+
 static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
 {
 	__ofono_ussd_ssc_register(cf->ussd, "21", cf_ss_control, cf, NULL);
@@ -1070,6 +1232,23 @@ static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
 	__ofono_ussd_ssc_register(cf->ussd, "004", cf_ss_control, cf, NULL);
 }
 
+static void cf_register_ss_controls_stk(struct ofono_call_forwarding *cf)
+{
+	__ofono_ussd_ssc_register_stk(cf->ussd, "21",
+					cf_ss_control_stk, cf, NULL);
+	__ofono_ussd_ssc_register_stk(cf->ussd, "67",
+					cf_ss_control_stk, cf, NULL);
+	__ofono_ussd_ssc_register_stk(cf->ussd, "61",
+					cf_ss_control_stk, cf, NULL);
+	__ofono_ussd_ssc_register_stk(cf->ussd, "62",
+					cf_ss_control_stk, cf, NULL);
+
+	__ofono_ussd_ssc_register_stk(cf->ussd, "002",
+					cf_ss_control_stk, cf, NULL);
+	__ofono_ussd_ssc_register_stk(cf->ussd, "004",
+					cf_ss_control_stk, cf, NULL);
+}
+
 static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
 {
 	__ofono_ussd_ssc_unregister(cf->ussd, "21");
@@ -1081,9 +1260,26 @@ static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
 	__ofono_ussd_ssc_unregister(cf->ussd, "004");
 }
 
+static void cf_unregister_ss_controls_stk(struct ofono_call_forwarding *cf)
+{
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "21");
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "67");
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "61");
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "62");
+
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "002");
+	__ofono_ussd_ssc_unregister_stk(cf->ussd, "004");
+}
+
 gboolean __ofono_call_forwarding_is_busy(struct ofono_call_forwarding *cf)
 {
-	return cf->pending ? TRUE : FALSE;
+	if (!cf)
+		return FALSE;
+
+	if (cf->pending || cf->req)
+		return TRUE;
+
+	return FALSE;
 }
 
 int ofono_call_forwarding_driver_register(const struct ofono_call_forwarding_driver *d)
@@ -1121,6 +1317,12 @@ static void call_forwarding_unregister(struct ofono_atom *atom)
 
 	if (cf->ussd_watch)
 		__ofono_modem_remove_atom_watch(modem, cf->ussd_watch);
+
+	if (cf->stk)
+		cf_unregister_ss_controls_stk(cf);
+
+	if (cf->stk_watch)
+		__ofono_modem_remove_atom_watch(modem, cf->stk_watch);
 }
 
 static void call_forwarding_remove(struct ofono_atom *atom)
@@ -1175,10 +1377,26 @@ struct ofono_call_forwarding *ofono_call_forwarding_create(struct ofono_modem *m
 	return cf;
 }
 
+static void stk_watch(struct ofono_atom *atom,
+			enum ofono_atom_watch_condition cond, void *data)
+{
+	struct ofono_call_forwarding *cf = data;
+
+	if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+		cf->stk = NULL;
+		return;
+	}
+
+	cf->stk = __ofono_atom_get_data(atom);
+	cf_register_ss_controls_stk(cf);
+}
+
 static void ussd_watch(struct ofono_atom *atom,
 			enum ofono_atom_watch_condition cond, void *data)
 {
 	struct ofono_call_forwarding *cf = data;
+	struct ofono_atom *stk_atom;
+	struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
 
 	if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
 		cf->ussd = NULL;
@@ -1187,6 +1405,16 @@ static void ussd_watch(struct ofono_atom *atom,
 
 	cf->ussd = __ofono_atom_get_data(atom);
 	cf_register_ss_controls(cf);
+
+	cf->stk_watch = __ofono_modem_add_atom_watch(modem,
+					OFONO_ATOM_TYPE_STK,
+					stk_watch, cf, NULL);
+
+	stk_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_STK);
+
+	if (stk_atom && __ofono_atom_get_registered(stk_atom))
+		stk_watch(stk_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
+				cf);
 }
 
 void ofono_call_forwarding_register(struct ofono_call_forwarding *cf)
diff --git a/src/ofono.h b/src/ofono.h
index 78e6be1..7ea6abc 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -298,11 +298,35 @@ typedef gboolean (*ofono_ussd_passwd_cb_t)(const char *sc,
 typedef void (*ofono_ussd_request_cb_t)(int error, int dcs,
 					const unsigned char *pdu, int len,
 					void *data);
+typedef void (*ofono_ss_request_cb_t)(const struct ofono_error *error,
+					void *data);
+typedef void (*ofono_ss_request_cancel_t)(void *ss);
+
+struct ofono_ss_request {
+	ofono_ss_request_cb_t cb;
+	void *user_data;
+	ofono_ss_request_cancel_t cancel;
+	void *ss;
+};
+
+typedef gboolean (*ofono_ussd_ssc_cb_stk_t)(int type, const char *sc,
+					const char *sia, const char *sib,
+					const char *sic, const char *dn,
+					struct ofono_ss_request *req,
+					void *data);
+typedef gboolean (*ofono_ussd_passwd_cb_stk_t)(const char *sc,
+					const char *old, const char *new,
+					struct ofono_ss_request *req,
+					void *data);
 
 gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
 					ofono_ussd_ssc_cb_t cb, void *data,
 					ofono_destroy_func destroy);
+gboolean __ofono_ussd_ssc_register_stk(struct ofono_ussd *ussd, const char *sc,
+					ofono_ussd_ssc_cb_stk_t cb, void *data,
+					ofono_destroy_func destroy);
 void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc);
+void __ofono_ussd_ssc_unregister_stk(struct ofono_ussd *ussd, const char *sc);
 
 gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
 					ofono_ussd_passwd_cb_t cb, void *data,
@@ -315,6 +339,10 @@ int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
 			ofono_ussd_request_cb_t cb, void *user_data);
 void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd);
 
+int __ofono_ussd_recognized_control_string_stk(struct ofono_ussd *ussd,
+						const char *ss_str,
+						struct ofono_ss_request *req);
+
 #include <ofono/netreg.h>
 
 typedef void (*ofono_netreg_status_notify_cb_t)(int status, int lac, int ci,
diff --git a/src/stk.c b/src/stk.c
index 60b308b..a152f19 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -74,6 +74,7 @@ struct ofono_stk {
 	char *idle_mode_text;
 	struct stk_icon_id idle_mode_icon;
 	struct timeval get_inkey_start_ts;
+	struct ofono_ss_request *ss_req;
 };
 
 struct envelope_op {
@@ -674,6 +675,13 @@ static GDBusSignalTable stk_signals[] = {
 	{ }
 };
 
+static gboolean set_result_type(struct stk_response *rsp,
+					enum stk_result_type type)
+{
+	rsp->result.type = type;
+	return TRUE;
+}
+
 static gboolean handle_command_more_time(const struct stk_command *cmd,
 						struct stk_response *rsp,
 						struct ofono_stk *stk)
@@ -759,6 +767,123 @@ static gboolean handle_command_send_sms(const struct stk_command *cmd,
 	return FALSE;
 }
 
+static void send_ss_cancel(struct ofono_stk *stk)
+{
+	if (!stk->ss_req || !stk->ss_req->cancel)
+		return;
+
+	stk->ss_req->cancel(stk->ss_req->ss);
+
+	g_free(stk->ss_req);
+	stk->ss_req = NULL;
+
+	if (stk->pending_cmd->send_ss.alpha_id &&
+			stk->pending_cmd->send_ss.alpha_id[0])
+		stk_alpha_id_unset(stk);
+}
+
+static void send_ss_cb(const struct ofono_error *error, void *data)
+{
+	struct ofono_stk *stk = data;
+	static struct ofono_error oe = { .type = OFONO_ERROR_TYPE_FAILURE };
+	struct stk_response rsp;
+	unsigned char addnl;
+
+	if (stk->pending_cmd->send_ss.alpha_id &&
+			stk->pending_cmd->send_ss.alpha_id[0])
+		stk_alpha_id_unset(stk);
+
+	memset(&rsp, 0, sizeof(rsp));
+
+	switch (error->type) {
+	case OFONO_ERROR_TYPE_NO_ERROR:
+		rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+		break;
+	default:
+		DBG("Send ss finishes with error type: %d", error->type);
+		rsp.result.type = STK_RESULT_TYPE_SS_RETURN_ERROR;
+		addnl = STK_RESULT_ADDNL_SS_PB_NO_SPECIFIC_CAUSE;
+		rsp.result.additional = &addnl;
+		rsp.result.additional_len = 1;
+		break;
+	}
+
+	g_free(stk->ss_req);
+	stk->ss_req = NULL;
+
+	if (stk_respond(stk, &rsp, stk_command_cb))
+		stk_command_cb(&oe, stk);
+}
+
+static gboolean handle_command_send_ss(const struct stk_command *cmd,
+					struct stk_response *rsp,
+					struct ofono_stk *stk)
+{
+	struct ofono_modem *modem = __ofono_atom_get_modem(stk->atom);
+	static unsigned char busy_on_ss_result[] = {
+				STK_RESULT_ADDNL_ME_PB_SS_BUSY };
+	static unsigned char busy_on_ussd_result[] = {
+				STK_RESULT_ADDNL_ME_PB_USSD_BUSY };
+	char *str = cmd->send_ss.ss.ss;
+	struct ofono_atom *ussd_atom;
+	struct ofono_ussd *ussd;
+	int result;
+	struct ofono_ss_request *req;
+
+	ussd_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_USSD);
+
+	if (!ussd_atom || !__ofono_atom_get_registered(ussd_atom))
+		return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+
+	ussd = __ofono_atom_get_data(ussd_atom);
+
+	if (__ofono_ussd_is_busy(ussd)) {
+		rsp->result.type = STK_RESULT_TYPE_TERMINAL_BUSY;
+		rsp->result.additional_len = sizeof(busy_on_ussd_result);
+		rsp->result.additional = busy_on_ussd_result;
+		return TRUE;
+	}
+
+	if (strlen(str) == 0)
+		return set_result_type(rsp,
+					STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+
+	req = g_try_new0(struct ofono_ss_request, 1);
+	req->cb = send_ss_cb;
+	req->user_data = stk;
+
+	result = __ofono_ussd_recognized_control_string_stk(ussd, str, req);
+
+	if (result != 0) {
+		DBG("Failed to send ss with result: %d", result);
+		g_free(req);
+	}
+
+	switch (result) {
+	case -EBUSY:
+		rsp->result.type = STK_RESULT_TYPE_TERMINAL_BUSY;
+		rsp->result.additional_len = sizeof(busy_on_ss_result);
+		rsp->result.additional = busy_on_ss_result;
+		return TRUE;
+	case -ENOSYS:
+	case -ENOMEM:
+		return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+	case 0:
+		stk->ss_req = req;
+		stk->cancel_cmd = send_ss_cancel;
+
+		if (cmd->send_ss.alpha_id && cmd->send_ss.alpha_id[0])
+			stk_alpha_id_set(stk, cmd->send_ss.alpha_id,
+						&cmd->send_ss.icon_id);
+
+		return FALSE;
+	case -EINVAL:
+	default:
+		return set_result_type(rsp,
+					STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+	}
+}
+
 static gboolean handle_command_set_idle_text(const struct stk_command *cmd,
 						struct stk_response *rsp,
 						struct ofono_stk *stk)
@@ -1958,6 +2083,11 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
 							&rsp, stk);
 		break;
 
+	case STK_COMMAND_TYPE_SEND_SS:
+		respond = handle_command_send_ss(stk->pending_cmd,
+							&rsp, stk);
+		break;
+
 	case STK_COMMAND_TYPE_SETUP_IDLE_MODE_TEXT:
 		respond = handle_command_set_idle_text(stk->pending_cmd,
 							&rsp, stk);
diff --git a/src/ussd.c b/src/ussd.c
index c0b7af8..6d16201 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -60,7 +60,9 @@ struct ofono_ussd {
 	DBusMessage *cancel;
 	int flags;
 	GSList *ss_control_list;
+	GSList *ss_control_list_stk;
 	GSList *ss_passwd_list;
+	GSList *ss_passwd_list_stk;
 	const struct ofono_ussd_driver *driver;
 	void *driver_data;
 	struct ofono_atom *atom;
@@ -138,6 +140,26 @@ gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
 	return TRUE;
 }
 
+gboolean __ofono_ussd_ssc_register_stk(struct ofono_ussd *ussd, const char *sc,
+					ofono_ussd_ssc_cb_stk_t cb, void *data,
+					ofono_destroy_func destroy)
+{
+	struct ssc_entry *entry;
+
+	if (!ussd)
+		return FALSE;
+
+	entry = ssc_entry_create(sc, cb, data, destroy);
+
+	if (!entry)
+		return FALSE;
+
+	ussd->ss_control_list_stk =
+			g_slist_prepend(ussd->ss_control_list_stk, entry);
+
+	return TRUE;
+}
+
 void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc)
 {
 	GSList *l;
@@ -155,6 +177,24 @@ void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc)
 	ussd->ss_control_list = g_slist_remove(ussd->ss_control_list, l->data);
 }
 
+void __ofono_ussd_ssc_unregister_stk(struct ofono_ussd *ussd, const char *sc)
+{
+	GSList *l;
+
+	if (!ussd)
+		return;
+
+	l = g_slist_find_custom(ussd->ss_control_list_stk, sc,
+				ssc_entry_find_by_service);
+
+	if (!l)
+		return;
+
+	ssc_entry_destroy(l->data);
+	ussd->ss_control_list_stk =
+			g_slist_remove(ussd->ss_control_list_stk, l->data);
+}
+
 gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
 					ofono_ussd_passwd_cb_t cb, void *data,
 					ofono_destroy_func destroy)
@@ -230,6 +270,45 @@ static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
 	return -ENOENT;
 }
 
+static int recognized_passwd_change_string_stk(struct ofono_ussd *ussd,
+						int type, char *sc, char *sia,
+						char *sib, char *sic,
+						char *sid, char *dn,
+						struct ofono_ss_request *req)
+{
+	GSList *l = ussd->ss_passwd_list;
+
+	switch (type) {
+	case SS_CONTROL_TYPE_ACTIVATION:
+	case SS_CONTROL_TYPE_REGISTRATION:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	if (strcmp(sc, "03") || strlen(dn))
+		return -ENOENT;
+
+	/* If SIC & SID don't match, then we just bail out here */
+	if (strcmp(sic, sid))
+		return EINVAL;
+
+	while ((l = g_slist_find_custom(l, sia,
+			ssc_entry_find_by_service)) != NULL) {
+		struct ssc_entry *entry = l->data;
+		ofono_ussd_passwd_cb_stk_t cb = entry->cb;
+		int result = cb(sia, sib, sic, req, entry->user);
+
+		if (result != -ENOENT)
+			return result;
+
+		l = l->next;
+	}
+
+	return -ENOENT;
+}
+
 static gboolean recognized_control_string(struct ofono_ussd *ussd,
 						const char *ss_str,
 						DBusMessage *msg)
@@ -298,6 +377,72 @@ out:
 	return ret;
 }
 
+int __ofono_ussd_recognized_control_string_stk(struct ofono_ussd *ussd,
+			const char *ss_str, struct ofono_ss_request *req)
+{
+	char *str = g_strdup(ss_str);
+	char *sc, *sia, *sib, *sic, *sid, *dn;
+	int type;
+	int ret = -ENOENT;
+	int result;
+
+	DBG("parsing control string");
+
+	if (parse_ss_control_string(str, &type, &sc,
+				&sia, &sib, &sic, &sid, &dn)) {
+		GSList *l = ussd->ss_control_list_stk;
+
+		DBG("Got parse result: %d, %s, %s, %s, %s, %s, %s",
+				type, sc, sia, sib, sic, sid, dn);
+
+		/* A password change string needs to be treated separately
+		 * because it uses a fourth SI and is thus not a valid
+		 * control string.  */
+		result = recognized_passwd_change_string_stk(ussd, type, sc,
+						sia, sib, sic, sid, dn, req);
+
+		if (result != -ENOENT) {
+			ret = result;
+			goto out;
+		}
+
+		if (*sid != '\0')
+			goto out;
+
+		while ((l = g_slist_find_custom(l, sc,
+				ssc_entry_find_by_service)) != NULL) {
+			struct ssc_entry *entry = l->data;
+			ofono_ussd_ssc_cb_stk_t cb = entry->cb;
+
+			result = cb(type, sc, sia, sib, sic, dn,
+							req, entry->user);
+
+			if (result != -ENOENT) {
+				ret = result;
+				goto out;
+			}
+
+			l = l->next;
+		}
+
+	}
+
+	/* TODO: Handle all strings that control voice calls */
+
+	/* TODO: Handle Multiple subscriber profile DN*59#SEND and *59#SEND
+	 */
+
+	/* Note: SIM PIN/PIN2 change and unblock and IMEI presentation
+	 * procedures are not handled by the daemon since they are not followed
+	 * by SEND and are not valid USSD requests.
+	 */
+
+out:
+	g_free(str);
+
+	return ret;
+}
+
 static const char *ussd_get_state_string(struct ofono_ussd *ussd)
 {
 	switch (ussd->state) {
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/4] Add macro for general result and additional info
  2010-10-18  8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
                   ` (2 preceding siblings ...)
  2010-10-18  8:00 ` [PATCH v3 4/4] cf: Handle send ss proactive command Yang Gu
@ 2010-10-20 23:22 ` Denis Kenzior
  3 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2010-10-20 23:22 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 225 bytes --]

Hi Yang,

On 10/18/2010 03:00 AM, Yang Gu wrote:
> ---
>  src/stkutil.h |   22 ++++++++++++++++++++++
>  1 files changed, 22 insertions(+), 0 deletions(-)
> 

This patch has been applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/4] stk: Support send ss response
  2010-10-18  8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
@ 2010-10-20 23:22   ` Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2010-10-20 23:22 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 204 bytes --]

Hi Yang,

On 10/18/2010 03:00 AM, Yang Gu wrote:
> ---
>  src/stkutil.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 

This patch has been applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-10-20 23:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-18  8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
2010-10-18  8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
2010-10-20 23:22   ` Denis Kenzior
2010-10-18  8:00 ` [PATCH v3 3/4] ss: Use errno for ssc handling functions Yang Gu
2010-10-18  8:00 ` [PATCH v3 4/4] cf: Handle send ss proactive command Yang Gu
2010-10-20 23:22 ` [PATCH v3 1/4] Add macro for general result and additional info Denis Kenzior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox