All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.