[1/4] Supplementary Services (de)activation and interrogation
diff mbox

Message ID 1436468544-20989-1-git-send-email-max.suraev@fairwaves.co
State New
Headers show

Commit Message

Max July 9, 2015, 7:02 p.m. UTC
Signed-off-by: Max <max.suraev@fairwaves.co>
---
 openbsc/include/openbsc/Makefile.am |   2 +-
 openbsc/include/openbsc/db.h        |   4 +
 openbsc/include/openbsc/gsm_04_80.h |  36 ++++++--
 openbsc/include/openbsc/ss.h        |  10 +++
 openbsc/include/openbsc/ussd.h      |  10 ---
 openbsc/src/libmsc/Makefile.am      |   2 +-
 openbsc/src/libmsc/db.c             |  89 +++++++++++++++++++
 openbsc/src/libmsc/gsm_04_08.c      |   4 +-
 openbsc/src/libmsc/gsm_04_80.c      |  65 ++++++++------
 openbsc/src/libmsc/ss.c             | 173 ++++++++++++++++++++++++++++++++++++
 openbsc/src/libmsc/ussd.c           |  87 ------------------
 11 files changed, 349 insertions(+), 133 deletions(-)
 create mode 100644 openbsc/include/openbsc/ss.h
 delete mode 100644 openbsc/include/openbsc/ussd.h
 create mode 100644 openbsc/src/libmsc/ss.c
 delete mode 100644 openbsc/src/libmsc/ussd.c

Patch
diff mbox

diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 254f43d..b19c413 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -2,7 +2,7 @@  noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
 		 gsm_subscriber.h gsm_04_11.h debug.h signal.h \
 		 misdn.h chan_alloc.h paging.h ctrl.h \
 		 trau_mux.h rs232.h openbscdefines.h rtp_proxy.h \
-		 bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
+		 bsc_rll.h mncc.h transaction.h ss.h gsm_04_80.h \
 		 silent_call.h mgcp.h meas_rep.h rest_octets.h \
 		 system_information.h handover.h mgcp_internal.h \
 		 vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index 6699a86..73c061b 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -79,4 +79,8 @@  int db_store_counter(struct osmo_counter *ctr);
 struct rate_ctr_group;
 int db_store_rate_ctr_group(struct rate_ctr_group *ctrg);
 
+/* Supplementary Services */
+int db_ss_interrogate_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t *ss_status);
+int db_ss_set_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t ss_status);
+
 #endif /* _DB_H */
diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h
index 0a60652..7139f95 100644
--- a/openbsc/include/openbsc/gsm_04_80.h
+++ b/openbsc/include/openbsc/gsm_04_80.h
@@ -3,16 +3,42 @@ 
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/gsm/protocol/gsm_04_80.h>
+#include <osmocom/gsm/protocol/gsm_09_02.h>
 #include <osmocom/gsm/gsm0480.h>
 
 struct gsm_subscriber_connection;
 
+/* FIXME: replace with libosmocore functions */
+static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
+{
+	uint8_t *data = msgb_push(msgb, 2);
+
+	data[0] = tag;
+	data[1] = msgb->len - 2;
+	return data;
+}
+
+static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
+                                           uint8_t value)
+{
+	uint8_t *data = msgb_push(msgb, 3);
+
+	data[0] = tag;
+	data[1] = 1;
+	data[2] = value;
+	return data;
+}
+
 int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
-			       const struct msgb *in_msg, const char* response_text, 
-			       const struct ussd_request *req);
-int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
-			     const struct msgb *msg, 
-			     const struct ussd_request *request);
+			       const char* response_text,
+			       const struct ss_request *req);
+int gsm0480_send_ss_return_result(struct gsm_subscriber_connection *conn,
+				  const struct ss_request *req,
+				  struct msgb *msg);
+int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn,
+			   const struct ss_request *request,
+			   uint8_t problem_category,
+			   uint8_t problem_code);
 
 int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text);
 int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn);
diff --git a/openbsc/include/openbsc/ss.h b/openbsc/include/openbsc/ss.h
new file mode 100644
index 0000000..92ce913
--- /dev/null
+++ b/openbsc/include/openbsc/ss.h
@@ -0,0 +1,10 @@ 
+#ifndef _SS_H
+#define _SS_H
+
+/* Handler function for mobile-originated SS messages */
+
+#include <osmocom/core/msgb.h>
+
+int handle_rcv_ss(struct gsm_subscriber_connection *conn, struct msgb *msg);
+
+#endif
diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h
deleted file mode 100644
index 2665468..0000000
--- a/openbsc/include/openbsc/ussd.h
+++ /dev/null
@@ -1,10 +0,0 @@ 
-#ifndef _USSD_H
-#define _USSD_H
-
-/* Handler function for mobile-originated USSD messages */
-
-#include <osmocom/core/msgb.h>
-
-int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
-
-#endif
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am
index aa7d8ae..de0ce66 100644
--- a/openbsc/src/libmsc/Makefile.am
+++ b/openbsc/src/libmsc/Makefile.am
@@ -16,7 +16,7 @@  libmsc_a_SOURCES =	auth.c \
 			silent_call.c \
 			sms_queue.c \
 			token_auth.c \
-			ussd.c \
+			ss.c \
 			vty_interface_layer3.c \
 			transaction.c \
 			osmo_msc.c ctrl_commands.c meas_feed.c
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 428f99b..25dd00e 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -41,6 +41,8 @@ 
 /* Semi-Private-Interface (SPI) for the subscriber code */
 void subscr_direct_free(struct gsm_subscriber *subscr);
 
+#include <osmocom/gsm/protocol/gsm_09_02.h>
+
 static char *db_basename = NULL;
 static char *db_dirname = NULL;
 static dbi_conn conn;
@@ -174,6 +176,15 @@  static const char *create_stmts[] = {
 		"sres BLOB NOT NULL, "
 		"kc BLOB NOT NULL "
 		")",
+	"CREATE TABLE IF NOT EXISTS SS_Status ("
+		"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
+		"subscriber INTEGER NOT NULL, "
+		"ss_code TINYINT UNSIGNED NOT NULL, "
+		"bs_code TINYINT UNSIGNED, "
+		"ss_status TINYINT UNSIGNED NOT NULL, "
+		"UNIQUE(subscriber, ss_code, bs_code), "
+		"FOREIGN KEY(subscriber) REFERENCES Subscriber (id) ON DELETE CASCADE ON UPDATE CASCADE "
+		")",
 };
 
 void db_error_func(dbi_conn conn, void *data)
@@ -1724,3 +1735,81 @@  int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
 
 	return 0;
 }
+
+int db_ss_interrogate_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t *ss_status)
+{
+	char buf[32];
+	dbi_result result;
+
+	/* Copy the id to a string as queryf with %llu is failing */
+	sprintf(buf, "%llu", subscr->id);
+	result = dbi_conn_queryf(conn,
+				 "SELECT ss_status FROM SS_Status "
+				 "WHERE subscriber = %s "
+				 "AND ss_code = %i AND bs_code = %i",
+				 buf, ss_code, bs_code);
+
+	if (!result) {
+		LOGP(DDB,
+		     LOGL_ERROR,
+		     "Failed to query ss_status for subscriber %llu, "
+		     "ss code 0x%02X, bs code 0x%02X\n",
+		     subscr->id, ss_code, bs_code);
+		return -EIO;
+	}
+	if (!dbi_result_next_row(result)) {
+		DEBUGP(DDB,
+		       "Failed to find ss_status for subscriber %llu, "
+		       "ss code 0x%02X, bs code 0x%02X\n",
+		       subscr->id, ss_code, bs_code);
+		dbi_result_free(result);
+		return -ENOENT;
+	}
+
+	*ss_status = dbi_result_get_uint(result, "ss_status");
+	DEBUGP(DDB,
+	       "Found ss_status for subscriber %llu, "
+	       "ss code 0x%02X, bs code 0x%02X: P:%d R:%d A:%d Q:%d\n",
+	       subscr->id, ss_code, bs_code,
+	       (*ss_status & GSM0902_SS_STATUS_P_BIT) && 1,
+	       (*ss_status & GSM0902_SS_STATUS_R_BIT) && 1,
+	       (*ss_status & GSM0902_SS_STATUS_A_BIT) && 1,
+	       (*ss_status & GSM0902_SS_STATUS_Q_BIT) && 1);
+
+	dbi_result_free(result);
+	return 0;
+}
+
+int db_ss_set_status(struct gsm_subscriber *subscr, uint8_t ss_code, uint8_t bs_code, uint8_t ss_status)
+{
+	char buf[32];
+	dbi_result result;
+
+	/* Copy the id to a string as queryf with %llu is failing */
+	sprintf(buf, "%llu", subscr->id);
+
+	result = dbi_conn_queryf(conn,
+				 "UPDATE SS_Status SET ss_status = %i "
+				 "WHERE subscriber = %s AND "
+				 "ss_code = %i AND bs_code = %i",
+				 ss_status, buf, ss_code, bs_code);
+
+	if (!result) {
+		LOGP(DDB, LOGL_ERROR,
+		     "Failed to set ss_status for subscriber %llu\n",
+		     subscr->id);
+		return -EIO;
+	}
+
+	DEBUGP(DDB,
+	       "Set ss_status for subscriber %llu, "
+	       "ss code 0x%02X, bs code 0x%02X: P:%d R:%d A:%d Q:%d\n",
+	       subscr->id, ss_code, bs_code,
+	       (ss_status & GSM0902_SS_STATUS_P_BIT) && 1,
+	       (ss_status & GSM0902_SS_STATUS_R_BIT) && 1,
+	       (ss_status & GSM0902_SS_STATUS_A_BIT) && 1,
+	       (ss_status & GSM0902_SS_STATUS_Q_BIT) && 1);
+
+	dbi_result_free(result);
+	return 0;
+}
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 29ab2ba..01f8f32 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -47,7 +47,7 @@ 
 #include <openbsc/trau_mux.h>
 #include <openbsc/rtp_proxy.h>
 #include <openbsc/transaction.h>
-#include <openbsc/ussd.h>
+#include <openbsc/ss.h>
 #include <openbsc/silent_call.h>
 #include <openbsc/bsc_api.h>
 #include <openbsc/osmo_msc.h>
@@ -3340,7 +3340,7 @@  int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
 		break;
 	case GSM48_PDISC_NC_SS:
 		release_anchor(conn);
-		rc = handle_rcv_ussd(conn, msg);
+		rc = handle_rcv_ss(conn, msg);
 		break;
 	default:
 		LOGP(DRLL, LOGL_NOTICE, "Unknown "
diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c
index b30f9ee..b20521a 100644
--- a/openbsc/src/libmsc/gsm_04_80.c
+++ b/openbsc/src/libmsc/gsm_04_80.c
@@ -39,31 +39,11 @@ 
 #include <osmocom/core/msgb.h>
 #include <osmocom/gsm/tlv.h>
 
-static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
-{
-	uint8_t *data = msgb_push(msgb, 2);
-
-	data[0] = tag;
-	data[1] = msgb->len - 2;
-	return data;
-}
-
-static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
-					    uint8_t value)
-{
-	uint8_t *data = msgb_push(msgb, 3);
-
-	data[0] = tag;
-	data[1] = 1;
-	data[2] = value;
-	return data;
-}
-
 
 /* Send response to a mobile-originated ProcessUnstructuredSS-Request */
 int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
-			       const struct msgb *in_msg, const char *response_text,
-			       const struct ussd_request *req)
+			       const char *response_text,
+			       const struct ss_request *req)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
@@ -109,16 +89,47 @@  int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
 	return gsm0808_submit_dtap(conn, msg, 0, 0);
 }
 
-int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
-			     const struct msgb *in_msg,
-			     const struct ussd_request *req)
+/* Send response to a mobile-originated Invoke */
+int gsm0480_send_ss_return_result(struct gsm_subscriber_connection *conn,
+                                  const struct ss_request *req,
+                                  struct msgb *msg)
+{
+	struct gsm48_hdr *gh;
+
+	/* Pre-pend the operation code */
+	msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
+
+	/* Wrap the contents as a sequence */
+	msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
+
+	/* Pre-pend the invoke ID */
+	msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+
+	/* Wrap this up as a Return Result component */
+	msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
+
+	/* Wrap the component in a Facility message */
+	msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
+
+	/* And finally pre-pend the L3 header */
+	gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
+					| (1<<7);  /* TI direction = 1 */
+	gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+
+	return gsm0808_submit_dtap(conn, msg, 0, 0);
+}
+
+int gsm0480_send_ss_reject(struct gsm_subscriber_connection *conn,
+			   const struct ss_request *req,
+			   uint8_t problem_category,
+			   uint8_t problem_code)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
 	/* First insert the problem code */
-	msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
-			GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
+	msgb_push_TLV1(msg, problem_category, problem_code);
 
 	/* Before it insert the invoke ID */
 	msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
diff --git a/openbsc/src/libmsc/ss.c b/openbsc/src/libmsc/ss.c
new file mode 100644
index 0000000..44a01ec
--- /dev/null
+++ b/openbsc/src/libmsc/ss.c
@@ -0,0 +1,173 @@ 
+/* Network-specific handling of mobile-originated SSs. */
+
+/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009 by Mike Haben <michael.haben@btinternet.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* This module defines the network-specific handling of mobile-originated
+   SS messages. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <openbsc/db.h>
+#include <openbsc/gsm_04_80.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
+#include <openbsc/osmo_msc.h>
+
+/* Declarations of USSD strings to be recognised */
+const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
+
+/* Forward declarations of network-specific handler functions */
+static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req);
+static int change_ss_activation(struct gsm_subscriber_connection *conn, uint8_t activate, const struct ss_request *req);
+static int interrogate_ss(struct gsm_subscriber_connection *conn, const struct ss_request *req);
+
+/* Entrypoint - handler function common to all mobile-originated SS */
+int handle_rcv_ss(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+	int rc;
+	struct ss_request req;
+	struct gsm48_hdr *gh;
+	uint8_t activate;
+
+	memset(&req, 0, sizeof(req));
+	gh = msgb_l3(msg);
+	rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
+
+	if (rc == 1) {
+
+		switch (req.opcode) {
+		case GSM0480_OP_CODE_PROCESS_USS_REQ:
+
+			if (req.ussd_text[0] == 0xFF)  /* Release-Complete */
+				return 0;
+
+			if (!strcmp(USSD_TEXT_OWN_NUMBER,
+				   (const char *)req.ussd_text)) {
+				DEBUGP(DMM, "USSD: Own number requested\n");
+				rc = send_own_number(conn, msg, &req);
+			} else {
+				DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text);
+				rc = gsm0480_send_ss_reject(conn, &req,
+							    GSM_0480_PROBLEM_CODE_TAG_INVOKE,
+							    GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION);
+			}
+
+			break;
+
+		case GSM0480_OP_CODE_ACTIVATE_SS:
+		case GSM0480_OP_CODE_DEACTIVATE_SS:
+			activate = (req.opcode == GSM0480_OP_CODE_ACTIVATE_SS);
+			rc = change_ss_activation(conn, activate, &req);
+			break;
+		case GSM0480_OP_CODE_INTERROGATE_SS:
+			rc = interrogate_ss(conn, &req);
+			break;
+		default:
+			DEBUGP(DMM, "Unhandled SS opcode %d\n", req.opcode);
+			rc = gsm0480_send_ss_reject(conn, &req,
+						    GSM_0480_PROBLEM_CODE_TAG_GENERAL,
+						    GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
+			break;
+		}
+
+	} else {
+		rc = gsm0480_send_ss_reject(conn, &req,
+					    GSM_0480_PROBLEM_CODE_TAG_GENERAL,
+					    GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE);
+	}
+
+	/* check if we can release it */
+	msc_release_connection(conn);
+	return rc;
+}
+
+/* A network-specific handler function */
+static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
+{
+	char *own_number = conn->subscr->extension;
+	char response_string[GSM_EXTENSION_LENGTH + 20];
+
+	/* Need trailing CR as EOT character */
+	snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
+	return gsm0480_send_ussd_response(conn, response_string, req);
+}
+
+static int change_ss_activation(struct gsm_subscriber_connection *conn, uint8_t activate, const struct ss_request *req)
+{
+	struct msgb *msg;
+	uint8_t ss_status;
+	int rc = db_ss_interrogate_status(conn->subscr,
+					  req->ss_code,
+					  GSM0902_TS_CODE_TELEPHONY,
+					  &ss_status);
+
+	if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) {
+		DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code);
+		return gsm0480_send_ss_reject(conn, req,
+					      GSM_0480_PROBLEM_CODE_TAG_INVOKE,
+					      GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION);
+	}
+
+	ss_status &= ~GSM0902_SS_STATUS_A_BIT;
+	ss_status |= (activate ? GSM0902_SS_STATUS_A_BIT : 0);
+
+	rc = db_ss_set_status(conn->subscr, req->ss_code,
+			      GSM0902_TS_CODE_TELEPHONY, ss_status);
+	if(rc < 0)
+		return gsm0480_send_ss_reject(conn, req,
+					      GSM_0480_PROBLEM_CODE_TAG_INVOKE,
+					      GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION);
+
+	msg = gsm48_msgb_alloc();
+	/* First put the payload into the message */
+	msgb_push_TLV1(msg, GSM0902_SS_DATA_SS_STATUS_TAG, ss_status);
+	/* Then wrap it as a Sequence of type SS-Data */
+	msgb_wrap_with_TL(msg, GSM0902_SS_INFO_SS_DATA_TAG);
+
+	return gsm0480_send_ss_return_result(conn, req, msg);
+}
+
+static int interrogate_ss(struct gsm_subscriber_connection *conn, const struct ss_request *req)
+{
+	struct msgb *msg;
+	uint8_t ss_status;
+	int rc = db_ss_interrogate_status(conn->subscr,
+					  req->ss_code,
+					  GSM0902_TS_CODE_TELEPHONY,
+					  &ss_status);
+
+	if(rc < 0 || !(ss_status & GSM0902_SS_STATUS_P_BIT)) {
+		DEBUGP(DMM, "SS 0x%02X not provisioned\n", req->ss_code);
+		return gsm0480_send_ss_reject(conn, req,
+					      GSM_0480_PROBLEM_CODE_TAG_INVOKE,
+					      GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION);
+	}
+
+	msg = gsm48_msgb_alloc();
+	/* Put the payload into the message */
+	msgb_push_TLV1(msg, GSM0902_SS_INTERR_SS_RES_SS_STATUS_TAG, ss_status);
+
+	return gsm0480_send_ss_return_result(conn, req, msg);
+}
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
deleted file mode 100644
index 7f01eae..0000000
--- a/openbsc/src/libmsc/ussd.c
+++ /dev/null
@@ -1,87 +0,0 @@ 
-/* Network-specific handling of mobile-originated USSDs. */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by Mike Haben <michael.haben@btinternet.com>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* This module defines the network-specific handling of mobile-originated
-   USSD messages. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <openbsc/gsm_04_80.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/debug.h>
-#include <openbsc/osmo_msc.h>
-
-/* Declarations of USSD strings to be recognised */
-const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
-
-/* Forward declarations of network-specific handler functions */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req);
-
-
-/* Entrypoint - handler function common to all mobile-originated USSDs */
-int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
-{
-	int rc;
-	struct ussd_request req;
-	struct gsm48_hdr *gh;
-
-	memset(&req, 0, sizeof(req));
-	gh = msgb_l3(msg);
-	rc = gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req);
-	if (!rc) {
-		DEBUGP(DMM, "Unhandled SS\n");
-		rc = gsm0480_send_ussd_reject(conn, msg, &req);
-		msc_release_connection(conn);
-		return rc;
-	}
-
-	/* Release-Complete */
-	if (req.text[0] == '\0')
-		return 0;
-
-	if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.text)) {
-		DEBUGP(DMM, "USSD: Own number requested\n");
-		rc = send_own_number(conn, msg, &req);
-	} else {
-		DEBUGP(DMM, "Unhandled USSD %s\n", req.text);
-		rc = gsm0480_send_ussd_reject(conn, msg, &req);
-	}
-
-	/* check if we can release it */
-	msc_release_connection(conn);
-	return rc;
-}
-
-/* A network-specific handler function */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req)
-{
-	char *own_number = conn->subscr->extension;
-	char response_string[GSM_EXTENSION_LENGTH + 20];
-
-	/* Need trailing CR as EOT character */
-	snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
-	return gsm0480_send_ussd_response(conn, msg, response_string, req);
-}