All of lore.kernel.org
 help / color / mirror / Atom feed
* Currently when sending a supplementary service control string via D-Bus, a
@ 2010-09-13  8:35 Yang Gu
  2010-09-13  8:35 ` [PATCH] stk: Handle send ss proactive command Yang Gu
  2010-09-13  8:46 ` [PATCH 0/1] " Gu, Yang
  0 siblings, 2 replies; 5+ messages in thread
From: Yang Gu @ 2010-09-13  8:35 UTC (permalink / raw)
  To: ofono

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


From Yang Gu <yang.gu@intel.com> # This line is ignored.
From: Yang Gu <yang.gu@intel.com>
Subject: 
In-Reply-To: 


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

* [PATCH] stk: Handle send ss proactive command
  2010-09-13  8:35 Currently when sending a supplementary service control string via D-Bus, a Yang Gu
@ 2010-09-13  8:35 ` Yang Gu
  2010-09-13  8:46 ` [PATCH 0/1] " Gu, Yang
  1 sibling, 0 replies; 5+ messages in thread
From: Yang Gu @ 2010-09-13  8:35 UTC (permalink / raw)
  To: ofono

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

---
 src/call-barring.c    |  168 ++++++++++++++++++++++---------------
 src/call-forwarding.c |  155 +++++++++++++++++++++-------------
 src/call-settings.c   |  220 +++++++++++++++++++++++++++----------------------
 src/ofono.h           |   15 +++-
 src/stk.c             |   98 ++++++++++++++++++++++
 src/stkutil.c         |    2 +
 src/stkutil.h         |   23 +++++
 src/ussd.c            |   78 ++++++++++++------
 8 files changed, 504 insertions(+), 255 deletions(-)

diff --git a/src/call-barring.c b/src/call-barring.c
index d235211..f504d07 100644
--- a/src/call-barring.c
+++ b/src/call-barring.c
@@ -48,6 +48,7 @@ static void set_query_next_lock(struct ofono_call_barring *cb);
 struct ofono_call_barring {
 	int flags;
 	DBusMessage *pending;
+	ofono_bool_t stk_pending;
 	int cur_locks[NUM_OF_BARRINGS];
 	int new_locks[NUM_OF_BARRINGS];
 	int query_start;
@@ -58,10 +59,12 @@ struct ofono_call_barring {
 	int ss_req_lock;
 	struct ofono_ssn *ssn;
 	struct ofono_ussd *ussd;
+	struct ofono_stk *stk;
 	unsigned int incoming_bar_watch;
 	unsigned int outgoing_bar_watch;
 	unsigned int ssn_watch;
 	unsigned int ussd_watch;
+	unsigned int stk_watch;
 	const struct ofono_call_barring_driver *driver;
 	void *driver_data;
 	struct ofono_atom *atom;
@@ -95,6 +98,36 @@ static struct call_barring_lock cb_locks[] = {
 #define CB_ALL_OUTGOING 6
 #define CB_ALL_INCOMING 7
 
+gboolean __ofono_call_barring_is_busy(struct ofono_call_barring *cb)
+{
+	if (!cb)
+		return FALSE;
+
+	if (cb->pending || cb->stk_pending)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void reply_error(struct ofono_call_barring *cb,
+				const struct ofono_error *error)
+{
+	if (cb->pending)
+		__ofono_dbus_pending_reply(&cb->pending,
+				__ofono_error_failed(cb->pending));
+	else
+		__ofono_stk_send_ss_response(cb->stk, &cb->stk_pending,	error);
+}
+
+static void set_pending(struct ofono_call_barring *cb,
+				struct ofono_ss_req *osr)
+{
+	if (osr->msg)
+		cb->pending = dbus_message_ref(osr->msg);
+	else
+		cb->stk_pending = TRUE;
+}
+
 static inline void emit_barring_changed(struct ofono_call_barring *cb,
 					int start, int end,
 					const char *type, int cls)
@@ -293,9 +326,8 @@ static void cb_ss_query_next_lock_callback(const struct ofono_error *error,
 					"successful, but query was not");
 
 		cb->flags &= ~CALL_BARRING_FLAG_CACHED;
+		reply_error(cb, error);
 
-		__ofono_dbus_pending_reply(&cb->pending,
-					__ofono_error_failed(cb->pending));
 		return;
 	}
 
@@ -307,7 +339,11 @@ static void cb_ss_query_next_lock_callback(const struct ofono_error *error,
 		return;
 	}
 
-	generate_ss_query_reply(cb);
+	if (cb->pending)
+		generate_ss_query_reply(cb);
+	else
+		__ofono_stk_send_ss_response(cb->stk, &cb->stk_pending, error);
+
 	update_barrings(cb, BEARER_CLASS_VOICE);
 }
 
@@ -328,8 +364,7 @@ static void cb_ss_set_lock_callback(const struct ofono_error *error,
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("Enabling/disabling Call Barring via SS failed");
-		__ofono_dbus_pending_reply(&cb->pending,
-					__ofono_error_failed(cb->pending));
+		reply_error(cb, error);
 		return;
 	}
 
@@ -359,25 +394,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_ss_req *osr, 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 (cb->pending) {
-		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 +415,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 +426,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 +448,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
 	 * We support query by querying all relevant types, since we must
@@ -433,7 +458,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;
@@ -442,16 +467,16 @@ 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;
-	cb->pending = dbus_message_ref(msg);
+	set_pending(cb, osr);
 
 	switch (type) {
 	case SS_CONTROL_TYPE_ACTIVATION:
@@ -472,44 +497,35 @@ 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)
 {
 	struct ofono_call_barring *cb = data;
-	DBusMessage *reply;
 
-	if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
-		reply = dbus_message_new_method_return(cb->pending);
-	else {
-		reply = __ofono_error_failed(cb->pending);
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("Changing Call Barring password via SS failed");
+		reply_error(cb, error);
+		return;
 	}
 
-	__ofono_dbus_pending_reply(&cb->pending, reply);
+	if (cb->pending)
+		__ofono_dbus_pending_reply(&cb->pending,
+				dbus_message_new_method_return(cb->pending));
+	else
+		__ofono_stk_send_ss_response(cb->stk, &cb->stk_pending, error);
 }
 
-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_ss_req *osr, void *data)
 {
 	struct ofono_call_barring *cb = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
-	DBusMessage *reply;
 	const char *fac;
 
-	if (cb->pending) {
-		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");
 
@@ -521,19 +537,16 @@ 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;
+
+	set_pending(cb, osr);
 
-	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)
@@ -580,11 +593,6 @@ static void cb_unregister_ss_controls(struct ofono_call_barring *cb)
 	__ofono_ussd_passwd_unregister(cb->ussd, "353");
 }
 
-gboolean __ofono_call_barring_is_busy(struct ofono_call_barring *cb)
-{
-	return cb->pending ? TRUE : FALSE;
-}
-
 static inline void cb_append_property(struct ofono_call_barring *cb,
 					DBusMessageIter *dict, int start,
 					int end, int cls, const char *property)
@@ -674,7 +682,7 @@ static DBusMessage *cb_get_properties(DBusConnection *conn, DBusMessage *msg,
 {
 	struct ofono_call_barring *cb = data;
 
-	if (cb->pending || __ofono_ussd_is_busy(cb->ussd))
+	if (__ofono_call_barring_is_busy(cb) || __ofono_ussd_is_busy(cb->ussd))
 		return __ofono_error_busy(msg);
 
 	if (!cb->driver->query)
@@ -827,7 +835,7 @@ static DBusMessage *cb_set_property(DBusConnection *conn, DBusMessage *msg,
 	int cls;
 	int mode;
 
-	if (cb->pending || __ofono_ussd_is_busy(cb->ussd))
+	if (__ofono_call_barring_is_busy(cb) || __ofono_ussd_is_busy(cb->ussd))
 		return __ofono_error_busy(msg);
 
 	if (!dbus_message_iter_init(msg, &iter))
@@ -899,7 +907,7 @@ static DBusMessage *cb_disable_all(DBusConnection *conn, DBusMessage *msg,
 	if (!cb->driver->set)
 		return __ofono_error_not_implemented(msg);
 
-	if (cb->pending || __ofono_ussd_is_busy(cb->ussd))
+	if (__ofono_call_barring_is_busy(cb) || __ofono_ussd_is_busy(cb->ussd))
 		return __ofono_error_busy(msg);
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &passwd,
@@ -946,7 +954,7 @@ static DBusMessage *cb_set_passwd(DBusConnection *conn, DBusMessage *msg,
 	if (!cb->driver->set_passwd)
 		return __ofono_error_not_implemented(msg);
 
-	if (cb->pending || __ofono_ussd_is_busy(cb->ussd))
+	if (__ofono_call_barring_is_busy(cb) || __ofono_ussd_is_busy(cb->ussd))
 		return __ofono_error_busy(msg);
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &old_passwd,
@@ -1150,6 +1158,19 @@ static void ussd_watch(struct ofono_atom *atom,
 	cb_register_ss_controls(cb);
 }
 
+static void stk_watch(struct ofono_atom *atom,
+			enum ofono_atom_watch_condition cond, void *data)
+{
+	struct ofono_call_barring *cb = data;
+
+	if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+		cb->stk = NULL;
+		return;
+	}
+
+	cb->stk = __ofono_atom_get_data(atom);
+}
+
 void ofono_call_barring_register(struct ofono_call_barring *cb)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
@@ -1157,6 +1178,7 @@ void ofono_call_barring_register(struct ofono_call_barring *cb)
 	struct ofono_modem *modem = __ofono_atom_get_modem(cb->atom);
 	struct ofono_atom *ssn_atom;
 	struct ofono_atom *ussd_atom;
+	struct ofono_atom *stk_atom;
 
 	if (!g_dbus_register_interface(conn, path,
 					OFONO_CALL_BARRING_INTERFACE,
@@ -1188,6 +1210,16 @@ void ofono_call_barring_register(struct ofono_call_barring *cb)
 		ussd_watch(ussd_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
 				cb);
 
+	cb->stk_watch = __ofono_modem_add_atom_watch(modem,
+					OFONO_ATOM_TYPE_STK,
+					stk_watch, cb, 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,
+				cb);
+
 	__ofono_atom_register(cb->atom, call_barring_unregister);
 }
 
diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index 5eae6cf..9161121 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;
+	ofono_bool_t stk_pending;
 	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;
@@ -77,6 +80,36 @@ struct cf_ss_request {
 	GSList *cf_list[4];
 };
 
+gboolean __ofono_call_forwarding_is_busy(struct ofono_call_forwarding *cf)
+{
+	if (!cf)
+		return FALSE;
+
+	if (cf->pending || cf->stk_pending)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void reply_error(struct ofono_call_forwarding *cf,
+				const struct ofono_error *error)
+{
+	if (cf->pending)
+		__ofono_dbus_pending_reply(&cf->pending,
+				__ofono_error_failed(cf->pending));
+	else
+		__ofono_stk_send_ss_response(cf->stk, &cf->stk_pending, error);
+}
+
+static void set_pending(struct ofono_call_forwarding *cf,
+				struct ofono_ss_req *osr)
+{
+	if (osr->msg)
+		cf->pending = dbus_message_ref(osr->msg);
+	else
+		cf->stk_pending = TRUE;
+}
+
 static gint cf_condition_compare(gconstpointer a, gconstpointer b)
 {
 	const struct ofono_call_forwarding_condition *ca = a;
@@ -430,7 +463,8 @@ static DBusMessage *cf_get_properties(DBusConnection *conn, DBusMessage *msg,
 	if (!cf->driver->query)
 		return __ofono_error_not_implemented(msg);
 
-	if (cf->pending || __ofono_ussd_is_busy(cf->ussd))
+	if (__ofono_call_forwarding_is_busy(cf) ||
+			__ofono_ussd_is_busy(cf->ussd))
 		return __ofono_error_busy(msg);
 
 	cf->pending = dbus_message_ref(msg);
@@ -586,7 +620,8 @@ static DBusMessage *cf_set_property(DBusConnection *conn, DBusMessage *msg,
 	int cls;
 	int type;
 
-	if (cf->pending || __ofono_ussd_is_busy(cf->ussd))
+	if (__ofono_call_forwarding_is_busy(cf) ||
+			__ofono_ussd_is_busy(cf->ussd))
 		return __ofono_error_busy(msg);
 
 	if (!dbus_message_iter_init(msg, &iter))
@@ -704,7 +739,8 @@ static DBusMessage *cf_disable_all(DBusConnection *conn, DBusMessage *msg,
 	if (!cf->driver->erasure)
 		return __ofono_error_not_implemented(msg);
 
-	if (cf->pending || __ofono_ussd_is_busy(cf->ussd))
+	if (__ofono_call_forwarding_is_busy(cf) ||
+			__ofono_ussd_is_busy(cf->ussd))
 		return __ofono_error_busy(msg);
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &strtype,
@@ -823,13 +859,11 @@ static void ss_set_query_cf_callback(const struct ofono_error *error, int total,
 {
 	struct ofono_call_forwarding *cf = data;
 	GSList *l;
-	DBusMessage *reply;
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		ofono_error("Setting succeeded, but query failed");
 		cf->flags &= ~CALL_FORWARDING_FLAG_CACHED;
-		reply = __ofono_error_failed(cf->pending);
-		__ofono_dbus_pending_reply(&cf->pending, reply);
+		reply_error(cf, error);
 		return;
 	}
 
@@ -840,8 +874,13 @@ static void ss_set_query_cf_callback(const struct ofono_error *error, int total,
 	cf->ss_req->cf_list[cf->query_next] = l;
 
 	if (cf->query_next == cf->query_end) {
-		reply = cf_ss_control_reply(cf, cf->ss_req);
-		__ofono_dbus_pending_reply(&cf->pending, reply);
+		if (cf->pending)
+			__ofono_dbus_pending_reply(&cf->pending,
+					cf_ss_control_reply(cf, cf->ss_req));
+		else
+			__ofono_stk_send_ss_response(cf->stk, &cf->stk_pending,
+							error);
+
 		g_free(cf->ss_req);
 		cf->ss_req = NULL;
 	}
@@ -866,9 +905,7 @@ static void cf_ss_control_callback(const struct ofono_error *error, void *data)
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("Error occurred during cf ss control set/erasure");
-
-		__ofono_dbus_pending_reply(&cf->pending,
-					__ofono_error_failed(cf->pending));
+		reply_error(cf, error);
 		g_free(cf->ss_req);
 		cf->ss_req = NULL;
 		return;
@@ -877,30 +914,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_ss_req *osr, 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;
+		return -ENOENT;
 
-	if (cf->pending) {
-		reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (__ofono_call_forwarding_is_busy(cf))
+		return EBUSY;
 
 	DBG("Received call forwarding ss control request");
 
@@ -920,13 +951,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
 	 * 22.030 Section 6.5.2 "The UE shall determine from the context
@@ -937,8 +968,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;
@@ -947,32 +978,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) {
@@ -993,27 +1024,19 @@ 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;
 	cf->ss_req->cls = cls;
 
-	cf->pending = dbus_message_ref(msg);
+	set_pending(cf, osr);
 
 	switch (cf->ss_req->cf_type) {
 	case CALL_FORWARDING_TYPE_ALL:
@@ -1062,12 +1085,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)
@@ -1092,11 +1110,6 @@ static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
 	__ofono_ussd_ssc_unregister(cf->ussd, "004");
 }
 
-gboolean __ofono_call_forwarding_is_busy(struct ofono_call_forwarding *cf)
-{
-	return cf->pending ? TRUE : FALSE;
-}
-
 int ofono_call_forwarding_driver_register(const struct ofono_call_forwarding_driver *d)
 {
 	DBG("driver: %p, name: %s", d, d->name);
@@ -1200,12 +1213,26 @@ static void ussd_watch(struct ofono_atom *atom,
 	cf_register_ss_controls(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);
+}
+
 void ofono_call_forwarding_register(struct ofono_call_forwarding *cf)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
 	const char *path = __ofono_atom_get_path(cf->atom);
 	struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
 	struct ofono_atom *ussd_atom;
+	struct ofono_atom *stk_atom;
 
 	if (!g_dbus_register_interface(conn, path,
 					OFONO_CALL_FORWARDING_INTERFACE,
@@ -1229,6 +1256,16 @@ void ofono_call_forwarding_register(struct ofono_call_forwarding *cf)
 		ussd_watch(ussd_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
 				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);
+
 	__ofono_atom_register(cf->atom, call_forwarding_unregister);
 }
 
diff --git a/src/call-settings.c b/src/call-settings.c
index 0c46a2a..4b8d71f 100644
--- a/src/call-settings.c
+++ b/src/call-settings.c
@@ -86,16 +86,49 @@ struct ofono_call_settings {
 	int cw;
 	int flags;
 	DBusMessage *pending;
+	ofono_bool_t stk_pending;
 	int ss_req_type;
 	int ss_req_cls;
 	enum call_setting_type ss_setting;
 	struct ofono_ussd *ussd;
+	struct ofono_stk *stk;
 	unsigned int ussd_watch;
+	unsigned int stk_watch;
 	const struct ofono_call_settings_driver *driver;
 	void *driver_data;
 	struct ofono_atom *atom;
 };
 
+gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs)
+{
+	if (!cs)
+		return FALSE;
+
+	if (cs->pending || cs->stk_pending)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void reply_error(struct ofono_call_settings *cs,
+				const struct ofono_error *error)
+{
+	if (cs->pending)
+		__ofono_dbus_pending_reply(&cs->pending,
+				__ofono_error_failed(cs->pending));
+	else
+		__ofono_stk_send_ss_response(cs->stk, &cs->stk_pending,	error);
+}
+
+static void set_pending(struct ofono_call_settings *cs,
+				struct ofono_ss_req *osr)
+{
+	if (osr->msg)
+		cs->pending = dbus_message_ref(osr->msg);
+	else
+		cs->stk_pending = TRUE;
+}
+
 static const char *clip_status_to_string(int status)
 {
 	switch (status) {
@@ -375,15 +408,17 @@ static void cw_ss_query_callback(const struct ofono_error *error, int status,
 		DBG("setting CW via SS failed");
 
 		cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
-		__ofono_dbus_pending_reply(&cs->pending,
-					__ofono_error_failed(cs->pending));
+		reply_error(cs, error);
 
 		return;
 	}
 
 	set_cw(cs, status, BEARER_CLASS_VOICE);
 
-	generate_cw_ss_query_reply(cs);
+	if (cs->pending)
+		generate_cw_ss_query_reply(cs);
+	else
+		__ofono_stk_send_ss_response(cs->stk, &cs->stk_pending, error);
 }
 
 static void cw_ss_set_callback(const struct ofono_error *error, void *data)
@@ -392,8 +427,7 @@ static void cw_ss_set_callback(const struct ofono_error *error, void *data)
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("setting CW via SS failed");
-		__ofono_dbus_pending_reply(&cs->pending,
-					__ofono_error_failed(cs->pending));
+		reply_error(cs, error);
 
 		return;
 	}
@@ -402,35 +436,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,
-				const char *sc, const char *sia,
+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)
+				const char *dn, struct ofono_ss_req *osr,
+				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 (cs->pending) {
-		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,15 +467,15 @@ 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;
-	cs->pending = dbus_message_ref(msg);
+	set_pending(cs, osr);
 
 	/* For the default case use the more readily accepted value */
 	if (cls == BEARER_CLASS_SS_DEFAULT)
@@ -477,13 +505,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,
@@ -528,8 +550,7 @@ static void clip_colp_colr_ss_query_cb(const struct ofono_error *error,
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("Error occurred during ss control query");
-		__ofono_dbus_pending_reply(&cs->pending,
-					__ofono_error_failed(cs->pending));
+		reply_error(cs, error);
 
 		return;
 	}
@@ -560,28 +581,26 @@ static void clip_colp_colr_ss_query_cb(const struct ofono_error *error,
 		return;
 	};
 
-	generate_ss_query_reply(cs, context, value);
+	if (cs->pending)
+		generate_ss_query_reply(cs, context, value);
+	else
+		__ofono_stk_send_ss_response(cs->stk, &cs->stk_pending, error);
 }
 
-static gboolean clip_colp_colr_ss(int type,
-				const char *sc, const char *sia,
+static int clip_colp_colr_ss(int type, const char *sc, const char *sia,
 				const char *sib, const char *sic,
-				const char *dn, DBusMessage *msg, void *data)
+				const char *dn, struct ofono_ss_req *osr,
+				void *data)
 {
 	struct ofono_call_settings *cs = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
 	void (*query_op)(struct ofono_call_settings *cs,
 				ofono_call_settings_status_cb_t cb, void *data);
 
 	if (!cs)
-		return FALSE;
+		return -ENOENT;
 
-	if (cs->pending) {
-		DBusMessage *reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+	if (__ofono_call_settings_is_busy(cs))
+		return EBUSY;
 
 	if (!strcmp(sc, "30")) {
 		cs->ss_setting = CALL_SETTING_TYPE_CLIP;
@@ -593,31 +612,23 @@ static gboolean clip_colp_colr_ss(int type,
 		cs->ss_setting = CALL_SETTING_TYPE_COLR;
 		query_op = cs->driver->colr_query;
 	} else {
-		return FALSE;
+		return -ENOENT;
 	}
 
 	if (type != SS_CONTROL_TYPE_QUERY || strlen(sia) || strlen(sib) ||
-		strlen(sic) || strlen(dn)) {
-		DBusMessage *reply = __ofono_error_invalid_format(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
-
-	if (!query_op) {
-		DBusMessage *reply = __ofono_error_not_implemented(msg);
-		g_dbus_send_message(conn, reply);
+			strlen(sic) || strlen(dn))
+		return EINVAL;
 
-		return TRUE;
-	}
+	if (!query_op)
+		return ENOSYS;
 
 	DBG("Received CLIP/COLR/COLP query ss control");
 
-	cs->pending = dbus_message_ref(msg);
+	set_pending(cs, osr);
 
 	query_op(cs, clip_colp_colr_ss_query_cb, cs);
 
-	return TRUE;
+	return 0;
 }
 
 static void clir_ss_query_callback(const struct ofono_error *error,
@@ -628,8 +639,7 @@ static void clir_ss_query_callback(const struct ofono_error *error,
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("setting clir via SS failed");
-		__ofono_dbus_pending_reply(&cs->pending,
-					__ofono_error_failed(cs->pending));
+		reply_error(cs, error);
 
 		return;
 	}
@@ -664,7 +674,10 @@ static void clir_ss_query_callback(const struct ofono_error *error,
 		value = "unknown";
 	};
 
-	generate_ss_query_reply(cs, "CallingLineRestriction", value);
+	if (cs->pending)
+		generate_ss_query_reply(cs, "CallingLineRestriction", value);
+	else
+		__ofono_stk_send_ss_response(cs->stk, &cs->stk_pending, error);
 
 	set_clir_network(cs, network);
 	set_clir_override(cs, override);
@@ -676,8 +689,8 @@ static void clir_ss_set_callback(const struct ofono_error *error, void *data)
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("setting clir via SS failed");
-		__ofono_dbus_pending_reply(&cs->pending,
-					__ofono_error_failed(cs->pending));
+
+		reply_error(cs, error);
 
 		return;
 	}
@@ -685,49 +698,37 @@ static void clir_ss_set_callback(const struct ofono_error *error, void *data)
 	cs->driver->clir_query(cs, clir_ss_query_callback, cs);
 }
 
-static gboolean clir_ss_control(int type,
-				const char *sc, const char *sia,
+static int clir_ss_control(int type, const char *sc, const char *sia,
 				const char *sib, const char *sic,
-				const char *dn, DBusMessage *msg, void *data)
+				const char *dn, struct ofono_ss_req *osr,
+				void *data)
 {
 	struct ofono_call_settings *cs = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
 
 	if (!cs)
-		return FALSE;
+		return -ENOENT;
 
 	if (strcmp(sc, "31"))
-		return FALSE;
-
-	if (cs->pending) {
-		DBusMessage *reply = __ofono_error_busy(msg);
-		g_dbus_send_message(conn, reply);
+		return -ENOENT;
 
-		return TRUE;
-	}
+	if (__ofono_call_settings_is_busy(cs))
+		return EBUSY;
 
 	/* This is the temporary form of CLIR, handled in voicecalls */
 	if (!strlen(sia) && !strlen(sib) & !strlen(sic) &&
-		strlen(dn) && type != SS_CONTROL_TYPE_QUERY)
-		return FALSE;
-
-	if (strlen(sia) || strlen(sib) || strlen(sic) || strlen(dn)) {
-		DBusMessage *reply = __ofono_error_invalid_format(msg);
-		g_dbus_send_message(conn, reply);
+			strlen(dn) && type != SS_CONTROL_TYPE_QUERY)
+		return -ENOENT;
 
-		return TRUE;
-	}
+	if (strlen(sia) || strlen(sib) || strlen(sic) || strlen(dn))
+		return EINVAL;
 
 	if ((type == SS_CONTROL_TYPE_QUERY && !cs->driver->clir_query) ||
-		(type != SS_CONTROL_TYPE_QUERY && !cs->driver->clir_set)) {
-		DBusMessage *reply = __ofono_error_not_implemented(msg);
-		g_dbus_send_message(conn, reply);
-
-		return TRUE;
-	}
+			(type != SS_CONTROL_TYPE_QUERY &&
+					!cs->driver->clir_set))
+		return ENOSYS;
 
 	cs->ss_setting = CALL_SETTING_TYPE_CLIR;
-	cs->pending = dbus_message_ref(msg);
+	set_pending(cs, osr);
 
 	switch (type) {
 	case SS_CONTROL_TYPE_REGISTRATION:
@@ -750,7 +751,7 @@ static gboolean clir_ss_control(int type,
 		break;
 	};
 
-	return TRUE;
+	return 0;
 }
 
 static void cs_register_ss_controls(struct ofono_call_settings *cs)
@@ -778,11 +779,6 @@ static void cs_unregister_ss_controls(struct ofono_call_settings *cs)
 		__ofono_ussd_ssc_unregister(cs->ussd, "77");
 }
 
-gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs)
-{
-	return cs->pending ? TRUE : FALSE;
-}
-
 static DBusMessage *generate_get_properties_reply(struct ofono_call_settings *cs,
 							DBusMessage *msg)
 {
@@ -955,7 +951,7 @@ static DBusMessage *cs_get_properties(DBusConnection *conn, DBusMessage *msg,
 {
 	struct ofono_call_settings *cs = data;
 
-	if (cs->pending || __ofono_ussd_is_busy(cs->ussd))
+	if (__ofono_call_settings_is_busy(cs) || __ofono_ussd_is_busy(cs->ussd))
 		return __ofono_error_busy(msg);
 
 	if (cs->flags & CALL_SETTINGS_FLAG_CACHED)
@@ -1132,7 +1128,7 @@ static DBusMessage *cs_set_property(DBusConnection *conn, DBusMessage *msg,
 	const char *property;
 	int cls;
 
-	if (cs->pending || __ofono_ussd_is_busy(cs->ussd))
+	if (__ofono_call_settings_is_busy(cs) || __ofono_ussd_is_busy(cs->ussd))
 		return __ofono_error_busy(msg);
 
 	if (!dbus_message_iter_init(msg, &iter))
@@ -1290,12 +1286,26 @@ static void ussd_watch(struct ofono_atom *atom,
 	cs_register_ss_controls(cs);
 }
 
+static void stk_watch(struct ofono_atom *atom,
+			enum ofono_atom_watch_condition cond, void *data)
+{
+	struct ofono_call_settings *cs = data;
+
+	if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+		cs->stk = NULL;
+		return;
+	}
+
+	cs->stk = __ofono_atom_get_data(atom);
+}
+
 void ofono_call_settings_register(struct ofono_call_settings *cs)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
 	const char *path = __ofono_atom_get_path(cs->atom);
 	struct ofono_modem *modem = __ofono_atom_get_modem(cs->atom);
 	struct ofono_atom *ussd_atom;
+	struct ofono_atom *stk_atom;
 
 	if (!g_dbus_register_interface(conn, path,
 					OFONO_CALL_SETTINGS_INTERFACE,
@@ -1319,6 +1329,16 @@ void ofono_call_settings_register(struct ofono_call_settings *cs)
 		ussd_watch(ussd_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
 				cs);
 
+	cs->stk_watch = __ofono_modem_add_atom_watch(modem,
+					OFONO_ATOM_TYPE_STK,
+					stk_watch, cs, 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,
+				cs);
+
 	__ofono_atom_register(cs->atom, call_settings_unregister);
 }
 
diff --git a/src/ofono.h b/src/ofono.h
index f1c0973..50d4f96 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -166,6 +166,12 @@ gboolean __ofono_modem_remove_atom_watch(struct ofono_modem *modem,
 
 void __ofono_atom_free(struct ofono_atom *atom);
 
+#include <gdbus.h>
+struct ofono_ss_req {
+	DBusMessage *msg;
+	gboolean stk;
+};
+
 #include <ofono/call-barring.h>
 
 gboolean __ofono_call_barring_is_busy(struct ofono_call_barring *cb);
@@ -228,6 +234,8 @@ unsigned int __ofono_sms_txq_submit(struct ofono_sms *sms, GSList *list,
 
 struct cbs;
 void __ofono_cbs_sim_download(struct ofono_stk *stk, const struct cbs *msg);
+void __ofono_stk_send_ss_response(struct ofono_stk *stk, gboolean *stk_pending,
+					const struct ofono_error *error);
 
 #include <ofono/ssn.h>
 
@@ -252,11 +260,11 @@ typedef gboolean (*ofono_ussd_ssc_cb_t)(int type,
 					const char *sc,
 					const char *sia, const char *sib,
 					const char *sic, const char *dn,
-					DBusMessage *msg, void *data);
+					struct ofono_ss_req *osr, void *data);
 
 typedef gboolean (*ofono_ussd_passwd_cb_t)(const char *sc,
 					const char *old, const char *new,
-					DBusMessage *msg, void *data);
+					struct ofono_ss_req *osr, void *data);
 
 gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
 					ofono_ussd_ssc_cb_t cb, void *data,
@@ -268,6 +276,9 @@ gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
 					ofono_destroy_func destroy);
 void __ofono_ussd_passwd_unregister(struct ofono_ussd *ussd, const char *sc);
 gboolean __ofono_ussd_is_busy(struct ofono_ussd *ussd);
+int __ofono_ussd_recognized_control_string(struct ofono_ussd *ussd,
+						const char *ss_str,
+						struct ofono_ss_req *osr);
 
 #include <ofono/netreg.h>
 
diff --git a/src/stk.c b/src/stk.c
index 04bfc65..e273914 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -648,6 +648,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)
@@ -731,6 +738,92 @@ static gboolean handle_command_send_sms(const struct stk_command *cmd,
 	return FALSE;
 }
 
+void __ofono_stk_send_ss_response(struct ofono_stk *stk, gboolean *stk_pending,
+					const struct ofono_error *error)
+{
+	static struct ofono_error oe = { .type = OFONO_ERROR_TYPE_FAILURE };
+	struct stk_response rsp;
+	unsigned char addnl[2];
+
+	*stk_pending = FALSE;
+
+	memset(&rsp, 0, sizeof(rsp));
+
+	switch (error->type) {
+	case OFONO_ERROR_TYPE_NO_ERROR:
+		rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+		break;
+	default:
+		rsp.result.type = STK_RESULT_TYPE_SS_RETURN_ERROR;
+		addnl[0] = (unsigned char) error->error;
+		addnl[1] = STK_RESULT_ADDNL_SS_PB_NO_SPECIFIC_CAUSE;
+		rsp.result.additional = addnl;
+		rsp.result.additional_len = 2;
+		break;
+	}
+
+	if (stk->pending_cmd->send_ss.alpha_id &&
+			stk->pending_cmd->send_ss.alpha_id[0])
+		stk_alpha_id_unset(stk);
+
+	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);
+	char *str = cmd->send_ss.ss.ss;
+	struct ofono_atom *ussd_atom;
+	struct ofono_ussd *ussd;
+	int result;
+	struct ofono_ss_req *osr;
+
+	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))
+		return set_result_type(rsp, STK_RESULT_TYPE_TERMINAL_BUSY);
+
+	if (strlen(str) == 0)
+		return set_result_type(rsp,
+					STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+
+	osr = g_try_new0(struct ofono_ss_req, 1);
+	if (!osr)
+		return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+
+	osr->stk = TRUE;
+
+	result = __ofono_ussd_recognized_control_string(ussd, str, osr);
+	g_free(osr);
+
+	switch (result) {
+	case EBUSY:
+		return set_result_type(rsp, STK_RESULT_TYPE_TERMINAL_BUSY);
+	case ENOSYS:
+	case ENOMEM:
+		return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+	case 0:
+		break;
+	case EINVAL:
+	default:
+		return set_result_type(rsp,
+					STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+	}
+
+	if (cmd->send_ss.alpha_id && cmd->send_ss.alpha_id[0])
+		stk_alpha_id_set(stk, cmd->send_ss.alpha_id);
+
+	return FALSE;
+}
+
 static gboolean handle_command_set_idle_text(const struct stk_command *cmd,
 						struct stk_response *rsp,
 						struct ofono_stk *stk)
@@ -1696,6 +1789,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/stkutil.c b/src/stkutil.c
index 3cfe06a..e21698b 100644
--- a/src/stkutil.c
+++ b/src/stkutil.c
@@ -5441,6 +5441,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;
diff --git a/src/stkutil.h b/src/stkutil.h
index c432df8..2b8f53a 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,27 @@ enum stk_result_type {
 	STK_RESULT_TYPE_MMS_ERROR =			0x3D,
 };
 
+enum stk_result_addnl_me_pb_fb {
+	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_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_BUSY_ON_SEND_DTMF =	0x09,
+	STK_RESULT_ADDNL_ME_PB_NO_NAA_ACTIVE =		0x0A
+};
+
+enum stk_result_addnl_me_pb_ob {
+	STK_RESULT_ADDNL_ME_PB_SS_BUSY =	0x03,
+	STK_RESULT_ADDNL_ME_PB_USSD_BUSY =	0x08
+};
+
+enum stk_result_addnl_ss_pb_ob {
+	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,
diff --git a/src/ussd.c b/src/ussd.c
index fbb07d2..7e8d1c8 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -182,11 +182,10 @@ void __ofono_ussd_passwd_unregister(struct ofono_ussd *ussd, const char *sc)
 	ussd->ss_passwd_list = g_slist_remove(ussd->ss_passwd_list, l->data);
 }
 
-static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
-						int type, char *sc,
-						char *sia, char *sib,
-						char *sic, char *sid,
-						char *dn, DBusMessage *msg)
+static int recognized_passwd_change_string(struct ofono_ussd *ussd, int type,
+						char *sc, char *sia, char *sib,
+						char *sic, char *sid, char *dn,
+						struct ofono_ss_req *osr)
 {
 	GSList *l = ussd->ss_passwd_list;
 
@@ -196,42 +195,40 @@ 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, osr, entry->user);
 
-		if (cb(sia, sib, sic, msg, entry->user))
-			return TRUE;
+		if (result >= 0)
+			return result;
 
 		l = l->next;
 	}
 
-	return FALSE;
+	return -ENOENT;
 }
 
-static gboolean recognized_control_string(struct ofono_ussd *ussd,
+int __ofono_ussd_recognized_control_string(struct ofono_ussd *ussd,
 						const char *ss_str,
-						DBusMessage *msg)
+						struct ofono_ss_req *osr)
 {
 	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");
 
@@ -245,9 +242,11 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
 		/* A password change string needs to be treated separately
 		 * 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, osr);
+
+		if (result >= 0) {
+			ret = result;
 			goto out;
 		}
 
@@ -259,8 +258,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, osr,
+								entry->user);
+
+			if (result >= 0) {
+				ret = result;
 				goto out;
 			}
 
@@ -447,6 +449,8 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
 {
 	struct ofono_ussd *ussd = data;
 	const char *str;
+	int result;
+	struct ofono_ss_req *osr;
 
 	if (ussd->pending)
 		return __ofono_error_busy(msg);
@@ -462,8 +466,30 @@ 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;
+
+	osr = g_try_new0(struct ofono_ss_req, 1);
+	if (!osr)
+		return __ofono_error_failed(msg);
+
+	osr->msg = msg;
+
+	result = __ofono_ussd_recognized_control_string(ussd, str, osr);
+	g_free(osr);
+
+	if (result >= 0) {
+		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;
+		}
+	}
 
 	DBG("No.., checking if this is a USSD string");
 	if (!valid_ussd_string(str))
-- 
1.7.0.4


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

* [PATCH 0/1] stk: Handle send ss proactive command
  2010-09-13  8:35 Currently when sending a supplementary service control string via D-Bus, a Yang Gu
  2010-09-13  8:35 ` [PATCH] stk: Handle send ss proactive command Yang Gu
@ 2010-09-13  8:46 ` Gu, Yang
  2010-09-15 12:12   ` Jeevaka.Badrappan
  1 sibling, 1 reply; 5+ messages in thread
From: Gu, Yang @ 2010-09-13  8:46 UTC (permalink / raw)
  To: ofono

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

Hi, 

>-----Original Message-----
>From: ofono-bounces(a)ofono.org [mailto:ofono-bounces(a)ofono.org] On Behalf Of
>Yang Gu
>Sent: Monday, September 13, 2010 4:36 PM
>To: ofono(a)ofono.org
>Subject: Currently when sending a supplementary service control string via D-Bus, a
>
>
From Yang Gu <yang.gu@intel.com> # This line is ignored.
>From: Yang Gu <yang.gu@intel.com>
>Subject:
>In-Reply-To:
>
>_______________________________________________
>ofono mailing list
>ofono(a)ofono.org
>http://lists.ofono.org/listinfo/ofono

I intended to send a description for the patch I sent just now, but seems it failed. Sorry for the inconvenience :(

Below is the description:
This patch is to handle send ss proactive command from SIM. 
Currently when sending a supplementary service control string via D-Bus, a series of functions would be called. For example, if we want to send a call barring activatioin string via D-Bus, these functions would be called: ussd_initiate()->recognized_control_string()->cb_ss_control()->cb_ss_set_lock_callback()->cb_ss_query_next_lock()->cb_ss_query_next_lock_callback(). To handle send ss command from SIM needs to follow the same way as D-Bus, so my target is to try the best to reuse these functions. However, currently these functions take the assumption that the calling is from D-Bus. My solution is to introduce a data structure named "ofono_ss_req" to replace original "DBusMessage *" parameter. 
Other main changes are to unify the return code of these functions and handle them centrally.

Comments are welcome!


Regards,
-Yang

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

* RE: [PATCH 0/1] stk: Handle send ss proactive command
  2010-09-13  8:46 ` [PATCH 0/1] " Gu, Yang
@ 2010-09-15 12:12   ` Jeevaka.Badrappan
  2010-09-15 17:06     ` Gu, Yang
  0 siblings, 1 reply; 5+ messages in thread
From: Jeevaka.Badrappan @ 2010-09-15 12:12 UTC (permalink / raw)
  To: ofono

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


Hi Yang,

> Below is the description:
> This patch is to handle send ss proactive command from SIM. 
> Currently when sending a supplementary service control string via
D-Bus, a series of functions would be called. For example, if we want to
send a call barring activatioin string via D-Bus, these 
> functions would be called:
ussd_initiate()->recognized_control_string()->cb_ss_control()->cb_ss_set
_lock_callback()->cb_ss_query_next_lock()->cb_ss_query_next_lock_callbac
k(). To handle send ss command > from SIM needs to follow the same way
as D-Bus, so my target is to try the best to reuse these functions.
However, currently these functions take the assumption that the calling
is from D-Bus. My 
> solution is to introduce a data structure named "ofono_ss_req" to
replace original "DBusMessage *" parameter. 
> Other main changes are to unify the return code of these functions and
handle them centrally.

> Comments are welcome!

Following the same control flow as normal case, requires rewriting some
of the existing functions to deal with both the cases like what you have
done now. Isn't it better to keep it separate? So that we won't end up
in introducing SAT specific handling in the normal use case also.

Proposed solution:

SS(eg: call forwarding, call barring) registers to the USSD by calling
__ofono_ussd_ssc_register with the service code, call back
function(normal_callback) and few other parameters. SS can also register
to the STK by calling __ofono_ussd_ssc_register with the service code,
call back function(stk_callback). normal_callback and stk_callback can
handle normal and stk use case respectively. More generic handling can
be moved to a separate function which normal_callback and stk_callback
functions can make use of. Also parsing/matching of the service strings
can be moved to utility. STK, USSD or anyother atoms can make use of the
parsing/matching(of service string) utility function.

Let me know your views on this.

Thanks and Regards,
jeevaka

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

* RE: [PATCH 0/1] stk: Handle send ss proactive command
  2010-09-15 12:12   ` Jeevaka.Badrappan
@ 2010-09-15 17:06     ` Gu, Yang
  0 siblings, 0 replies; 5+ messages in thread
From: Gu, Yang @ 2010-09-15 17:06 UTC (permalink / raw)
  To: ofono

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

Hi jeevaka,



>-----Original Message-----
>From: ofono-bounces(a)ofono.org [mailto:ofono-bounces(a)ofono.org] On Behalf Of
>Jeevaka.Badrappan(a)elektrobit.com
>Sent: Wednesday, September 15, 2010 8:12 PM
>To: ofono(a)ofono.org
>Subject: RE: [PATCH 0/1] stk: Handle send ss proactive command
>
>
>Hi Yang,
>
>> Below is the description:
>> This patch is to handle send ss proactive command from SIM.
>> Currently when sending a supplementary service control string via
>D-Bus, a series of functions would be called. For example, if we want to
>send a call barring activatioin string via D-Bus, these
>> functions would be called:
>ussd_initiate()->recognized_control_string()->cb_ss_control()->cb_ss_set
>_lock_callback()->cb_ss_query_next_lock()->cb_ss_query_next_lock_callbac
>k(). To handle send ss command > from SIM needs to follow the same way
>as D-Bus, so my target is to try the best to reuse these functions.
>However, currently these functions take the assumption that the calling
>is from D-Bus. My
>> solution is to introduce a data structure named "ofono_ss_req" to
>replace original "DBusMessage *" parameter.
>> Other main changes are to unify the return code of these functions and
>handle them centrally.
>
>> Comments are welcome!
>
>Following the same control flow as normal case, requires rewriting some
>of the existing functions to deal with both the cases like what you have
>done now. Isn't it better to keep it separate? So that we won't end up
>in introducing SAT specific handling in the normal use case also.
>
>Proposed solution:
>
>SS(eg: call forwarding, call barring) registers to the USSD by calling
>__ofono_ussd_ssc_register with the service code, call back
>function(normal_callback) and few other parameters. SS can also register
>to the STK by calling __ofono_ussd_ssc_register with the service code,
>call back function(stk_callback). normal_callback and stk_callback can
>handle normal and stk use case respectively. More generic handling can
>be moved to a separate function which normal_callback and stk_callback
>functions can make use of. Also parsing/matching of the service strings
>can be moved to utility. STK, USSD or anyother atoms can make use of the
>parsing/matching(of service string) utility function.
>
>Let me know your views on this.

Thank you for the comments!

But if we handle stk logic in separate functions, we would have to duplicate:
In ussd.c, 
	recognized_control_string()
	recognized_passwd_change_string()
	ussd->ss_control_list
in <ss>.c:
    <ss>_ss_control() and other registered functions  // We may extract most of logic as a utility function, but we have to set the pending or the indication for stk request
    Various call back functions

I don't want to duplicate all these functions for stk, especially the two functions in ussd.c. Thinking about the case we may support at server (oFono has the ability to parse incoming at command, talk with modem in its specific language, at command or proprietary protocol, and send back the response) someday, you may need to duplicate all these functions again for it. 
In my opinion, the request from D-Bus isn't so "normal". Each atom provides a set of functions (services) that can be requested by others, either the request from D-Bus, or request from other atoms, such as stk and at server. Current functions take the assumption that all the requests are all from D-Bus. What I want to do is just to break this assumption, and my current solution is easy to be extended to support the at server case. 
What do you think about?

Regards,
-Yang

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

end of thread, other threads:[~2010-09-15 17:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-13  8:35 Currently when sending a supplementary service control string via D-Bus, a Yang Gu
2010-09-13  8:35 ` [PATCH] stk: Handle send ss proactive command Yang Gu
2010-09-13  8:46 ` [PATCH 0/1] " Gu, Yang
2010-09-15 12:12   ` Jeevaka.Badrappan
2010-09-15 17:06     ` Gu, Yang

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.