@@ -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 \
@@ -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 */
@@ -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);
new file mode 100644
@@ -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
deleted file mode 100644
@@ -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
@@ -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
@@ -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;
+}
@@ -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 "
@@ -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);
new file mode 100644
@@ -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);
+}
deleted file mode 100644
@@ -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);
-}
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