aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc
diff options
context:
space:
mode:
authorSergey.Kostanbaev <Sergey.Kostanbaev@gmail.com>2016-02-09 20:21:08 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2017-02-07 18:59:54 +0300
commitd4839fe14a0d060933f0006d10dc932375a7c7d6 (patch)
treea640aa5741fa5f75646e6b3e779957639eb8294e /openbsc/src/libmsc
parentdb0e216845a7859bf878a891e2a210dbef6395df (diff)
manual merge SS from sup-ussd-on-master-ss-wip
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r--openbsc/src/libmsc/Makefile.am2
-rw-r--r--openbsc/src/libmsc/gsm_04_80.c167
-rw-r--r--openbsc/src/libmsc/gsm_sup.c7
-rw-r--r--openbsc/src/libmsc/gsm_ussd_map.c93
-rw-r--r--openbsc/src/libmsc/gsm_ussd_map_proto.c212
-rw-r--r--openbsc/src/libmsc/ussd.c517
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c10
7 files changed, 684 insertions, 324 deletions
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am
index f9bcf2f37..c06b2960d 100644
--- a/openbsc/src/libmsc/Makefile.am
+++ b/openbsc/src/libmsc/Makefile.am
@@ -47,6 +47,8 @@ libmsc_a_SOURCES = \
osmo_msc.c \
ctrl_commands.c \
meas_feed.c \
+ gsm_ussd_map_proto.c \
+ gsm_ussd_map.c \
$(NULL)
if BUILD_SMPP
diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c
index a8cf3e9bf..716fe751f 100644
--- a/openbsc/src/libmsc/gsm_04_80.c
+++ b/openbsc/src/libmsc/gsm_04_80.c
@@ -39,7 +39,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
-
+/* This function can handle ASN1 length up to 255 which is enough for USSD */
static inline unsigned char *msgb_wrap_with_ASN1_TL(struct msgb *msgb, uint8_t tag)
{
uint16_t origlen = msgb->len;
@@ -75,56 +75,135 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
return data;
}
+static inline unsigned char *msgb_wrap_with_L(struct msgb *msgb)
+{
+ uint8_t *data = msgb_push(msgb, 1);
+
+ data[0] = msgb->len - 1;
+ 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,
- int response_text_len,
- uint8_t response_lang,
- const char *response_text,
- const struct ussd_request *req,
- uint8_t code,
- uint8_t ctype,
- uint8_t mtype)
+/* Compose universial USSD packet invoke/return_result payload */
+struct msgb *gsm0480_compose_ussd_component(struct ss_request* req)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP");
+ uint8_t *ptr8;
+
+ /* First put the payload text into the message */
+ ptr8 = msgb_put(msg, 0);
+
+ memcpy(ptr8, req->ussd_text, req->ussd_text_len);
+ msgb_put(msg, req->ussd_text_len);
+
+ /* Then wrap it as an Octet String */
+ msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG);
+
+ /* Pre-pend the DCS octet string */
+ msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language);
+
+ /* Then wrap these as a Sequence */
+ msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
+
+ if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) {
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
+
+ /* Wrap the operation code and IA5 string as a sequence */
+ msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
+
+ /* Pre-pend the invoke ID */
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+ } else if (req->component_type == GSM0480_CTYPE_INVOKE) {
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
+
+ /* Pre-pend the invoke ID */
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+ } else {
+ abort();
+ }
+
+ /* Wrap this up as an Invoke or a Return Result component */
+ msgb_wrap_with_ASN1_TL(msg, req->component_type);
+ return msg;
+}
+
+#ifndef NO_GSM0480_SEND_FUNC
+
+int gsm0480_send_component(struct gsm_subscriber_connection *conn,
+ struct msgb *msg,
+ struct ss_header* reqhdr)
+{
+#if 0
+ struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
uint8_t *ptr8;
- int response_len;
ptr8 = msgb_put(msg, 0);
- if (response_text_len < 0) {
- /* First put the payload text into the message */
- gsm_7bit_encode_n_ussd(ptr8, msgb_tailroom(msg), response_text, &response_len);
- msgb_put(msg, response_len);
- response_lang = 0x0F;
+ memcpy(ptr8, component, reqhdr->component_length);
+ msgb_put(msg, reqhdr->component_length);
+#endif
+ struct gsm48_hdr *gh;
+
+ if (reqhdr->message_type == GSM0480_MTYPE_REGISTER ||
+ reqhdr->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
+ /* Wrap the component in a Facility message, it's not ASN1 */
+ msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
+ } else if (reqhdr->message_type == GSM0480_MTYPE_FACILITY) {
+ /* For GSM0480_MTYPE_FACILITY it's LV not TLV */
+ msgb_wrap_with_L(msg);
} else {
- memcpy(ptr8, response_text, response_text_len);
- msgb_put(msg, response_text_len);
+ abort();
}
+ /* And finally pre-pend the L3 header */
+ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+ gh->proto_discr = GSM48_PDISC_NC_SS | reqhdr->transaction_id
+ | (1<<7); /* TI direction = 1 */
+ gh->msg_type = reqhdr->message_type;
+
+ DEBUGP(DSS, "Sending SS to mobile: %s\n", msgb_hexdump(msg));
+
+ return gsm0808_submit_dtap(conn, msg, 0, 0);
+}
+
+#if 0
+/* Compose universial SS packet except Reject opcodes */
+int gsm0480_send_ussd(struct gsm_subscriber_connection *conn,
+ struct ss_request* req)
+{
+ struct msgb *msg = gsm48_msgb_alloc();
+ struct gsm48_hdr *gh;
+ uint8_t *ptr8;
+
+ /* First put the payload text into the message */
+ ptr8 = msgb_put(msg, 0);
+
+ memcpy(ptr8, req->ussd_text, req->ussd_text_len);
+ msgb_put(msg, req->ussd_text_len);
+
/* Then wrap it as an Octet String */
msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG);
/* Pre-pend the DCS octet string */
- msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, response_lang);
+ msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language);
/* Then wrap these as a Sequence */
msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
- if (ctype == GSM0480_CTYPE_RETURN_RESULT) {
+ if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) {
/* Pre-pend the operation code */
- msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, code);
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
/* Wrap the operation code and IA5 string as a sequence */
msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
/* Pre-pend the invoke ID */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
- } else if (ctype == GSM0480_CTYPE_INVOKE) {
+ } else if (req->component_type == GSM0480_CTYPE_INVOKE) {
/* Pre-pend the operation code */
- msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, code);
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
/* Pre-pend the invoke ID */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
@@ -132,16 +211,16 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
abort();
}
- /* Wrap this up as a Return Result component */
- msgb_wrap_with_ASN1_TL(msg, ctype);
+ /* Wrap this up as an Invoke or a Return Result component */
+ msgb_wrap_with_ASN1_TL(msg, req->component_type);
- if (mtype == GSM0480_MTYPE_REGISTER ||
- mtype == GSM0480_MTYPE_RELEASE_COMPLETE) {
+ if (req->message_type == GSM0480_MTYPE_REGISTER ||
+ req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
/* Wrap the component in a Facility message, it's not ASN1 */
msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
- } else if (mtype == GSM0480_MTYPE_FACILITY) {
- uint8_t *data = msgb_push(msg, 1);
- data[0] = msg->len - 1;
+ } else if (req->message_type == GSM0480_MTYPE_FACILITY) {
+ /* For GSM0480_MTYPE_FACILITY it's LV not TLV */
+ msgb_wrap_with_L(msg);
} else {
abort();
}
@@ -149,42 +228,48 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
/* 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 */
+ | (1<<7); /* TI direction = 1 */
+ gh->msg_type = req->message_type;
- gh->msg_type = mtype;
-
- DEBUGP(DSUP, "Sending USSD to mobile: %s\n", msgb_hexdump(msg));
+ DEBUGP(DSS, "Sending USSD to mobile: %s\n", msgb_hexdump(msg));
return gsm0808_submit_dtap(conn, msg, 0, 0);
}
+#endif
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
- const struct msgb *in_msg,
- const struct ussd_request *req)
+ uint8_t invoke_id,
+ uint8_t transaction_id)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ");
- struct gsm48_hdr *gh;
+ struct ss_header ssh;
/* First insert the problem code */
msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
/* Before it insert the invoke ID */
- msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
/* Wrap this up as a Reject component */
msgb_wrap_with_ASN1_TL(msg, GSM0480_CTYPE_REJECT);
+ /* Prepare data for L3 header */
+ ssh.transaction_id = transaction_id;
+ ssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+ return gsm0480_send_component(conn, msg, &ssh);
+#if 0
/* 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;
- gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
+ gh->proto_discr |= transaction_id | (1<<7); /* TI direction = 1 */
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return gsm0808_submit_dtap(conn, msg, 0, 0);
+#endif
}
int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, const char *text)
@@ -202,3 +287,5 @@ int msc_send_ussd_release_complete(struct gsm_subscriber_connection *conn)
return -1;
return gsm0808_submit_dtap(conn, msg, 0, 0);
}
+
+#endif
diff --git a/openbsc/src/libmsc/gsm_sup.c b/openbsc/src/libmsc/gsm_sup.c
index f9edec352..9dc8f191e 100644
--- a/openbsc/src/libmsc/gsm_sup.c
+++ b/openbsc/src/libmsc/gsm_sup.c
@@ -32,6 +32,7 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/ussd.h>
+#if 0
enum {
FMAP_MSISDN = 0x80
};
@@ -171,7 +172,7 @@ static int rx_uss_message(const uint8_t* data, size_t len)
return on_ussd_response(&ss, extention);
}
-
+#endif
static int subscr_tx_sup_message(struct gprs_gsup_client *sup_client,
struct gsm_subscriber *subscr,
@@ -438,11 +439,11 @@ static int subscr_rx_sup_message(struct gprs_gsup_client *sup_client, struct msg
struct gprs_gsup_message gsup_msg = {0};
struct gsm_subscriber *subscr;
-
+#if 0
if (*data == GPRS_GSUP_MSGT_MAP) {
return rx_uss_message(data, data_len);
}
-
+#endif
rc = gprs_gsup_decode(data, data_len, &gsup_msg);
if (rc < 0) {
LOGP(DSUP, LOGL_ERROR,
diff --git a/openbsc/src/libmsc/gsm_ussd_map.c b/openbsc/src/libmsc/gsm_ussd_map.c
new file mode 100644
index 000000000..7ca84b133
--- /dev/null
+++ b/openbsc/src/libmsc/gsm_ussd_map.c
@@ -0,0 +1,93 @@
+/* GSM USSD external MAP interface */
+
+/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.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/>.
+ *
+ */
+
+#include <openbsc/gsm_ussd_map.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/debug.h>
+#include <openbsc/db.h>
+#include <openbsc/chan_alloc.h>
+#include <openbsc/gsm_04_08_gprs.h>
+#include <openbsc/gprs_gsup_messages.h>
+#include <openbsc/gprs_gsup_client.h>
+#include <openbsc/osmo_msc.h>
+#include <openbsc/gprs_utils.h>
+#include <openbsc/ussd.h>
+
+
+int ussd_map_tx_message(struct gsm_network* net,
+ struct ss_header *req,
+ const char* extension,
+ uint32_t ref,
+ const uint8_t* component_data)
+{
+ struct msgb *msg = gprs_gsup_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ subscr_uss_message(msg, req, extension, ref, component_data);
+
+ return gprs_gsup_client_send(net->ussd_sup_client, msg);
+}
+
+
+static int ussd_map_rx_message_int(struct gsm_network *net, const uint8_t* data, size_t len)
+{
+ char extension[32] = {0};
+ uint32_t ref;
+ struct ss_header ss;
+ memset(&ss, 0, sizeof(ss));
+
+ if (rx_uss_message_parse(data, len, &ss, &ref, extension, sizeof(extension))) {
+ LOGP(DSS, LOGL_ERROR, "Can't parse SUP MAP SS message\n");
+ return -1;
+ }
+
+ LOGP(DSS, LOGL_ERROR, "Got type=0x%02x len=%d\n",
+ ss.message_type, ss.component_length);
+
+ return on_ussd_response(net, ref, &ss, data + ss.component_offset, extension);
+}
+
+static int ussd_map_rx_message(struct gprs_gsup_client *sup_client, struct msgb *msg)
+{
+ uint8_t *data = msgb_l2(msg);
+ size_t data_len = msgb_l2len(msg);
+ struct gsm_network *gsmnet = (struct gsm_network *)sup_client->data;
+
+ if (*data != GPRS_GSUP_MSGT_USSD_MAP) {
+ return -1;
+ }
+
+ return ussd_map_rx_message_int(gsmnet, data, data_len);
+}
+
+int ussd_map_read_cb(struct gprs_gsup_client *sup_client, struct msgb *msg)
+{
+ int rc;
+
+ rc = ussd_map_rx_message(sup_client, msg);
+ msgb_free(msg);
+ if (rc < 0)
+ return -1;
+
+ return rc;
+}
diff --git a/openbsc/src/libmsc/gsm_ussd_map_proto.c b/openbsc/src/libmsc/gsm_ussd_map_proto.c
new file mode 100644
index 000000000..1d48efbd5
--- /dev/null
+++ b/openbsc/src/libmsc/gsm_ussd_map_proto.c
@@ -0,0 +1,212 @@
+/* GSM USSD external MAP protocol on pseudo TCAP */
+
+/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.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/>.
+ *
+ */
+
+#include <openbsc/gsm_ussd_map.h>
+#include <openbsc/gsm_ussd_map_proto.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/debug.h>
+#include <openbsc/db.h>
+#include <openbsc/chan_alloc.h>
+#include <openbsc/gsm_04_08_gprs.h>
+#include <openbsc/gprs_gsup_messages.h>
+#include <openbsc/gprs_gsup_client.h>
+#include <openbsc/osmo_msc.h>
+#include <openbsc/gprs_utils.h>
+#include <openbsc/ussd.h>
+
+/*
+* 0 - GPRS_GSUP_MSGT_USSD_MAP constant
+* 1 - LEN
+* 2 - message_type [ REGISTER / FACILITY / RELEASE COMPLETE ]
+* 3,4,5,6 - tid ID associated with the session
+* 7 - FMAP_MSISDN constant
+* 8 - extention_len
+* 9..x - extention
+* x+1 .. original MAP message
+*/
+
+int subscr_uss_message(struct msgb *msg,
+ struct ss_header *req,
+ const char* extension,
+ uint32_t ref,
+ const uint8_t* component_data)
+{
+ uint8_t bcd_lvlen;
+ uint8_t offset = 0;
+ uint8_t *gsup_indicator;
+
+ gsup_indicator = msgb_put(msg, 7);
+
+ /* First byte should always be GPRS_GSUP_MSGT_USSD_MAP */
+ gsup_indicator[offset++] = GPRS_GSUP_MSGT_USSD_MAP;
+ gsup_indicator[offset++] = 0; // Total length
+ gsup_indicator[offset++] = req->message_type;
+
+ gsup_indicator[offset++] = ref >> 24;
+ gsup_indicator[offset++] = ref >> 16;
+ gsup_indicator[offset++] = ref >> 8;
+ gsup_indicator[offset++] = ref;
+
+ if (extension) {
+ gsup_indicator[offset++] = FMAP_MSISDN;
+ bcd_lvlen = gsm48_encode_bcd_number(gsup_indicator + offset,
+ 32, 0, extension);
+
+ offset += bcd_lvlen;
+ msgb_put(msg, bcd_lvlen + 1);
+ }
+
+ if (component_data) {
+ msgb_put(msg, req->component_length);
+ memcpy(gsup_indicator + offset, component_data, req->component_length);
+ }
+
+ gsup_indicator[1] = offset + req->component_length - 2; //except GPRS_GSUP_MSGT_USSD_MAP and length field
+ return 0;
+#if 0
+ gsup_indicator[6] = req->component_type;
+
+ /* invokeId */
+ msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
+
+ /* opCode */
+ msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
+
+ if (req->ussd_text_len > 0) {
+ msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language);
+ }
+
+ if (extension) {
+ uint8_t bcd_buf[32];
+ bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
+ extension);
+ msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
+ }
+
+ /* fill actual length */
+ gsup_indicator[7] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);;
+
+ /* wrap with GSM0480_CTYPE_INVOKE */
+ // gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
+ // gsup_indicator = msgb_push(msgb, 1);
+ // gsup_indicator[0] = GPRS_GSUP_MSGT_MAP;
+ return 0;
+#endif
+}
+
+
+
+int rx_uss_message_parse(const uint8_t* data,
+ size_t len,
+ struct ss_header *ss,
+ uint32_t *pref,
+ char* extention,
+ size_t extention_len)
+{
+ uint8_t ext_len;
+ const uint8_t* const_data = data + 1; // Skip constant
+ uint32_t ref;
+ int total_len;
+
+ if (len < 7)
+ return -1;
+
+ /* skip GPRS_GSUP_MSGT_MAP */
+ total_len = *(const_data++);
+ ss->message_type = *(const_data++);
+
+ ref = ((uint32_t)(*(const_data++))) << 24;
+ ref |= ((uint32_t)(*(const_data++))) << 16;
+ ref |= ((uint32_t)(*(const_data++))) << 8;
+ ref |= ((uint32_t)(*(const_data++)));
+ if (pref)
+ *pref = ref;
+
+ total_len -= 4 + 1; // ref + sizeof(len)
+
+ if (*const_data == FMAP_MSISDN) {
+ ext_len = *(++const_data);
+ if (extention) {
+ gsm48_decode_bcd_number(extention,
+ extention_len,
+ const_data,
+ 0);
+ }
+ const_data += ext_len + 1;
+ total_len -= ext_len + 2; // tag FMAP_MSISDN + sizeof(len)
+ }
+
+ ss->component_offset = const_data - data;
+ ss->component_length = total_len; //data[ss->component_offset + 1];
+
+ return 0;
+#if 0
+ ss->component_type = *(++const_data);
+
+ /* skip full len and move to component id */
+ const_data += 2;
+
+ if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
+ return -1;
+ }
+ const_data += 2;
+ ss->invoke_id = *const_data;
+ const_data++;
+
+ //
+ if (*const_data != GSM0480_OPERATION_CODE) {
+ return -1;
+ }
+ const_data += 2;
+ ss->opcode = *const_data;
+ const_data++;
+
+
+ while (const_data - data < len) {
+ uint8_t len;
+ switch (*const_data) {
+ case ASN1_OCTET_STRING_TAG:
+ ss->ussd_text_len = len = (*(++const_data) - 1);
+ ss->ussd_text_language = *(++const_data);
+ memcpy(ss->ussd_text,
+ ++const_data,
+ (len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
+ const_data += len;
+ break;
+
+ case FMAP_MSISDN:
+ len = *(++const_data);
+ gsm48_decode_bcd_number(extention,
+ extention_len,
+ const_data,
+ 0);
+ const_data += len + 1;
+ break;
+ default:
+ DEBUGP(DSS, "Unknown code: %d\n", *const_data);
+ return -1;
+ }
+ }
+
+ return 0;
+#endif
+}
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
index b31f3e1a0..ac032439e 100644
--- a/openbsc/src/libmsc/ussd.c
+++ b/openbsc/src/libmsc/ussd.c
@@ -33,378 +33,341 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
#include <openbsc/osmo_msc.h>
-#include <openbsc/gsm_sup.h>
+#include <openbsc/gsm_ussd_map.h>
#include <openbsc/ussd.h>
+#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/gsm0480.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <openbsc/transaction.h>
-struct gsm_ussd {
- struct llist_head ussqueue;
+/* Last uniq generated session id */
+static uint32_t s_uniq_ussd_sessiod_id = 0;
- uint8_t uniq_id; /**< System wide uniq ID */
+/* Forward declaration of USSD handler for USSD MAP interface */
+static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg);
- uint8_t invoke_id;
- uint8_t transaction_id;
-
- uint8_t mobile_originated;
+/* Declarations of USSD strings to be recognised */
+const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
- struct gsm_subscriber_connection *conn;
-};
+/* Forward declarations of network-specific handler functions */
+static int send_own_number(struct gsm_subscriber_connection *conn,
+ const struct ss_header *reqhdr,
+ const struct ss_request *req);
-static unsigned s_ussd_open_sessions = 0;
-static uint64_t s_uniq_ussd_sessiod_id = 0;
-static LLIST_HEAD(s_active_ussd_sessions);
-static struct llist_head *get_active_ussd_sessions(void)
+/* Entrypoint - handler function common to all mobile-originated USSDs */
+int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
- return &s_active_ussd_sessions;
-}
+ int rc;
+ struct ss_header reqhdr;
+ struct ss_request req;
+ char request_string[MAX_LEN_USSD_STRING + 1];
+ struct gsm48_hdr *gh;
+ if (conn->subscr->group->net->ussd_sup_client)
+ return handle_rcv_ussd_sup(conn, msg);
-static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* conn,
- uint8_t tid,
- uint8_t mo)
-{
- struct gsm_network* net = conn->bts->network;
- struct gsm_ussd* m = talloc_zero(net, struct gsm_ussd);
- if (!m)
- return NULL;
-
- m->conn = conn;
- m->uniq_id = s_uniq_ussd_sessiod_id++;
- m->transaction_id = tid;
- m->mobile_originated = mo;
- ++s_ussd_open_sessions;
-
- INIT_LLIST_HEAD(&m->ussqueue);
- llist_add_tail(&m->ussqueue, &s_active_ussd_sessions);
-
- DEBUGP(DMM, "Alloc USSD session: %d (open: %d)\n", m->uniq_id, s_ussd_open_sessions);
- return m;
-}
+ memset(&req, 0, sizeof(req));
+ memset(&reqhdr, 0, sizeof(reqhdr));
+ gh = msgb_l3(msg);
+ rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &reqhdr);
+ if (!rc) {
+ DEBUGP(DSS, "Incorrect SS header\n");
+ msc_release_connection(conn);
+ return rc;
+ }
-static void ussd_session_free(struct gsm_ussd* s)
-{
- --s_ussd_open_sessions;
- DEBUGP(DMM, "Free USSD session: %d (open: %d)\n", s->uniq_id, s_ussd_open_sessions);
- llist_del(&s->ussqueue);
- talloc_free(s);
-}
+ rc = gsm0480_parse_ss_facility(gh->data + reqhdr.component_offset,
+ reqhdr.component_length,
+ &req);
+ if (!rc) {
+ DEBUGP(DSS, "Unhandled SS\n");
+ // TODO req.invoke_id may not be set!!!
+ rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
+ msc_release_connection(conn);
+ return rc;
+ }
-static struct gsm_ussd* get_by_uniq_id(uint8_t uniq_id)
-{
- struct gsm_ussd* c;
- llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) {
- if (c->uniq_id == uniq_id) {
- DEBUGP(DMM, "uniq_id %d has %s extention\n",
- uniq_id, c->conn->subscr->extension);
- return c;
- }
+ if (reqhdr.message_type == GSM0480_MTYPE_RELEASE_COMPLETE)
+ return 0;
+
+ if (reqhdr.message_type != GSM0480_MTYPE_REGISTER ||
+ req.component_type != GSM0480_CTYPE_INVOKE ||
+ req.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ ||
+ req.ussd_text_language != 0x0f)
+ {
+ DEBUGP(DSS, "Unexpected SS\n");
+ rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
+ msc_release_connection(conn);
+ return rc;
}
- DEBUGP(DMM, "uniq_id %d hasn't been found\n", uniq_id);
- return NULL;
+ gsm_7bit_decode_n_ussd(request_string, MAX_LEN_USSD_STRING, req.ussd_text, req.ussd_text_len);
+
+ if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)request_string)) {
+ DEBUGP(DSS, "USSD: Own number requested\n");
+ rc = send_own_number(conn, &reqhdr, &req);
+ } else {
+ DEBUGP(DSS, "Unhandled USSD %s\n", request_string);
+ rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
+ }
+
+ /* check if we can release it */
+ msc_release_connection(conn);
+ return rc;
}
-static struct gsm_ussd* get_by_iid(struct gsm_subscriber_connection *conn, uint8_t invoke_id)
+/* A network-specific handler function */
+static int send_own_number(struct gsm_subscriber_connection *conn,
+ const struct ss_header *reqhdr,
+ const struct ss_request *req)
{
- struct gsm_ussd* c;
- llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) {
- if (c->conn == conn && c->invoke_id == invoke_id) {
- DEBUGP(DMM, "invoke_id %d has %s extention\n",
- invoke_id, c->conn->subscr->extension);
- return c;
- }
- }
+ struct ss_request rss;
+ struct ss_header rssh;
- DEBUGP(DMM, "invoke_id %d hasn't been found\n", invoke_id);
- return NULL;
+ char *own_number = conn->subscr->extension;
+ char response_string[GSM_EXTENSION_LENGTH + 20];
+ int response_len;
+
+ /* Need trailing CR as EOT character */
+ snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
+
+ memset(&rss, 0, sizeof(rss));
+ gsm_7bit_encode_n_ussd(rss.ussd_text, MAX_LEN_USSD_STRING, response_string, &response_len);
+ rss.ussd_text_len = response_len;
+ rss.ussd_text_language = 0x0f;
+
+ rss.component_type = GSM0480_CTYPE_RETURN_RESULT;
+ rss.invoke_id = req->invoke_id;
+ rss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ;
+
+ rssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+ rssh.transaction_id = reqhdr->transaction_id;
+
+ return gsm0480_send_component(conn,
+ gsm0480_compose_ussd_component(&rss),
+ &rssh);
}
-static struct gsm_ussd* get_by_tid(struct gsm_subscriber_connection *conn, uint8_t transaction_id)
+
+static int ussd_sup_send_reject(struct gsm_network *conn, uint32_t ref)
{
- struct gsm_ussd* c;
- llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) {
- if (c->conn == conn && c->transaction_id == transaction_id) {
- DEBUGP(DMM, "transaction_id %d has %s extention\n",
- transaction_id, c->conn->subscr->extension);
- return c;
- }
- }
+ struct ss_header rej;
+ rej.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+ rej.component_length = 0;
- DEBUGP(DMM, "transaction_id %d hasn't been found\n", transaction_id);
- return NULL;
+#if 0
+ rej.component_type = GSM0480_CTYPE_REJECT;
+ rej.invoke_id = invokeid;
+ rej.opcode = opcode;
+ rej.ussd_text_len = 0;
+#endif
+ return ussd_map_tx_message(conn, &rej, NULL, ref, NULL);
}
-// From SUP
-int on_ussd_response(const struct ss_request *req, const char *extention)
+/* Callback from USSD MAP interface */
+int on_ussd_response(struct gsm_network *net,
+ uint32_t ref,
+ struct ss_header *reqhdr,
+ const uint8_t* component,
+ const char *extention)
{
- struct ussd_request ussd_req;
- struct gsm_ussd* ussdq;
- memset(&ussd_req, 0, sizeof(ussd_req));
+ struct gsm_trans *trans = trans_find_by_callref(net, ref);
int rc = 0;
+ struct msgb *msg;
+ uint8_t *ptr8;
- switch (req->message_type) {
+ switch (reqhdr->message_type) {
case GSM0480_MTYPE_REGISTER:
- DEBUGP(DMM, "Network originated USSD messages isn't supported yet!\n");
+ DEBUGP(DSS, "Network originated USSD messages isn't supported yet!\n");
- //TODO Send to sup rejection
+ ussd_sup_send_reject(net, ref);
return 0;
case GSM0480_MTYPE_FACILITY:
case GSM0480_MTYPE_RELEASE_COMPLETE:
- // FIXME add uinq_id field
- ussdq = get_by_uniq_id(req->invoke_id);
- if (!ussdq) {
- DEBUGP(DMM, "No session was found for uniq_id: %d!\n",
- req->invoke_id);
- // TODO SUP Reject
+ if (!trans) {
+ DEBUGP(DSS, "No session was found for ref: %d!\n",
+ ref);
+
+ ussd_sup_send_reject(net, ref);
return 0;
}
break;
default:
- DEBUGP(DMM, "Unknown message type 0x%02x\n", req->message_type);
- // TODO SUP Reject
+ DEBUGP(DSS, "Unknown message type 0x%02x\n", reqhdr->message_type);
+ ussd_sup_send_reject(net, ref);
return 0;
}
- ussd_req.transaction_id = ussdq->transaction_id;
- ussd_req.invoke_id = ussdq->invoke_id;
+#if 0
+ req->invoke_id = trans->ss.invoke_id;
+ req->transaction_id = (trans->transaction_id << 4) ^ 0x80;
if (req->component_type != GSM0480_CTYPE_REJECT) {
- rc = gsm0480_send_ussd_response(ussdq->conn,
- NULL,
- (req->ussd_text_language == 0x80) ? -1 : req->ussd_text_len,
- req->ussd_text_language,
- (const char *)req->ussd_text,
- &ussd_req,
- req->opcode,
- req->component_type,
- req->message_type);
+ rc = gsm0480_send_ussd(trans->conn, req);
} else {
- rc = gsm0480_send_ussd_reject(ussdq->conn, NULL, &ussd_req);
+ rc = gsm0480_send_ussd_reject(trans->conn, req);
}
+#endif
+ msg = gsm48_msgb_alloc();
+ ptr8 = msgb_put(msg, 0);
+
+ memcpy(ptr8, component, reqhdr->component_length);
+ msgb_put(msg, reqhdr->component_length);
+
+ rc = gsm0480_send_component(trans->conn, msg, reqhdr);
- if (req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
- msc_release_connection(ussdq->conn);
- ussd_session_free(ussdq);
+ if (reqhdr->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
+ struct gsm_subscriber_connection* conn = trans->conn;
+
+ trans_free(trans);
+ msc_release_connection(conn);
}
return rc;
}
-static int ussd_sup_send_reject(struct gsm_subscriber_connection *conn,
- uint8_t uniq_id, uint8_t opcode)
+static int get_invoke_id(const uint8_t* data, uint8_t len, uint8_t* pinvoke_id)
{
- struct ss_request rej;
- rej.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
- rej.component_type = GSM0480_CTYPE_REJECT;
- rej.invoke_id = uniq_id;
- rej.opcode = opcode;
- rej.ussd_text_len = 0;
+ /* 0: CTYPE tag
+ * 1..x: CTYPE len
+ * x: INVOKE_ID tag
+ * x+1: INVOKE_ID len
+ * x+2: INVOKE_ID value
+ */
+ if (len < 5)
+ return 0;
- return subscr_tx_uss_message(&rej, conn->subscr);
+ unsigned inv_offset = 2;
+ switch (data[0]) {
+ case GSM0480_CTYPE_INVOKE:
+ case GSM0480_CTYPE_RETURN_RESULT:
+ if (data[1] > 0x80)
+ inv_offset += data[1] & 0x7f;
+ if (inv_offset + 2 >= len)
+ return 0;
+ if (data[inv_offset] != GSM0480_COMPIDTAG_INVOKE_ID)
+ return 0;
+ *pinvoke_id = data[inv_offset + 2];
+ return 1;
+ }
+ return 0;
}
-/* Entrypoint - handler function common to all mobile-originated USSDs */
-int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
+/* Handler function common to all mobile-originated USSDs in case if USSD MAP enabled */
+static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
int rc = 0;
- struct gsm48_hdr *gh;
- struct ss_request req;
- struct gsm_ussd* ussdq = NULL;
- struct ussd_request ussd_req;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct ss_header reqhdr;
+ struct gsm_trans *trans = NULL;
+ uint8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
+ uint8_t invoke_id = 0;
- memset(&req, 0, sizeof(req));
- memset(&ussd_req, 0, sizeof(ussd_req));
+ if (!conn->subscr)
+ return -EIO;
- DEBUGP(DMM, "handle ussd: %s\n", msgb_hexdump(msg));
+ memset(&reqhdr, 0, sizeof(reqhdr));
- gh = msgb_l3(msg);
- rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
+ DEBUGP(DSS, "handle ussd tid=%d: %s\n", transaction_id, msgb_hexdump(msg));
+ trans = trans_find_by_id(conn, GSM48_PDISC_NC_SS, transaction_id);
+
+ rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &reqhdr);
if (!rc) {
- DEBUGP(DMM, "Unhandled SS\n");
- ussdq = get_by_tid(conn, req.transaction_id);
- if (ussdq) {
- ussd_sup_send_reject(conn, ussdq->uniq_id, 0);
- goto failed_transaction;
+ DEBUGP(DSS, "Incorrect SS header\n");
+ if (!trans) {
+ goto release_conn;
}
- goto transaction_not_found;
+ /* don't know how to process */
+ goto failed_transaction;
}
- switch (req.message_type) {
+
+ switch (reqhdr.message_type) {
case GSM0480_MTYPE_REGISTER:
- ussdq = ussd_session_alloc(conn, req.transaction_id, USSD_MO);
- if (!ussdq) {
- DEBUGP(DMM, "Failed to create new session\n");
+ if (trans) {
+ /* we already have a transaction, ignore this message */
+ goto release_conn;
+ }
+ if (!get_invoke_id(gh->data + reqhdr.component_offset,
+ reqhdr.component_length,
+ &invoke_id)) {
+ DEBUGP(DSS, "Incorrect InvokeID in transaction\n");
+ goto release_conn;
+ }
+
+ trans = trans_alloc(conn->bts->network, conn->subscr,
+ GSM48_PDISC_NC_SS,
+ transaction_id, s_uniq_ussd_sessiod_id++);
+ if (!trans) {
+ DEBUGP(DSS, "Failed to create new ussd transaction\n");
goto transaction_not_found;
}
- ussdq->invoke_id = req.invoke_id;
+
+ trans->conn = conn;
+ trans->ss.invoke_id = invoke_id;
+ trans->ss.mo = 1;
+ trans->ss.dirty = 1;
break;
+
case GSM0480_MTYPE_FACILITY:
- ussdq = get_by_tid(conn, req.transaction_id);
- if (!ussdq) {
- ussdq = get_by_iid(conn, req.invoke_id);
- if (!ussdq) {
- DEBUGP(DMM, "no session found invoke_id=%d tid=%d\n",
- req.invoke_id, req.transaction_id);
- goto transaction_not_found;
+ if (!trans) {
+ DEBUGP(DSS, "No session found tid=%d\n",
+ transaction_id);
+
+ if (!get_invoke_id(gh->data + reqhdr.component_offset,
+ reqhdr.component_length,
+ &invoke_id)) {
+ DEBUGP(DSS, "Incorrect InvokeID in transaction\n");
+ goto release_conn;
}
+
+ goto transaction_not_found;
}
break;
case GSM0480_MTYPE_RELEASE_COMPLETE:
- // FIXME handle parsing in libosmocore
- ussdq = get_by_tid(conn, req.transaction_id);
- if (!ussdq) {
- DEBUGP(DMM, "RELEASE_COMPLETE to non-existing transaction!\n");
+ if (!trans) {
+ DEBUGP(DSS, "RELEASE_COMPLETE to non-existing transaction!\n");
goto release_conn;
}
- ussd_session_free(ussdq);
- ussd_sup_send_reject(conn, ussdq->uniq_id, req.opcode);
+ trans_free(trans);
goto release_conn;
}
- req.invoke_id = ussdq->uniq_id;
- rc = subscr_tx_uss_message(&req, conn->subscr);
+ rc = ussd_map_tx_message(conn->subscr->group->net, &reqhdr,
+ conn->subscr->extension, trans->callref,
+ gh->data + reqhdr.component_offset);
if (rc) {
- DEBUGP(DMM, "Unable tp send uss over sup reason: %d\n", rc);
+ /* do not send reject if we failed with the message */
+ trans->ss.dirty = 0;
+
+ DEBUGP(DSS, "Unable tp send uss over sup reason: %d\n", rc);
goto failed_transaction;
}
return 0;
failed_transaction:
- ussd_session_free(ussdq);
+ trans_free(trans);
transaction_not_found:
- ussd_req.invoke_id = req.invoke_id;
- ussd_req.transaction_id = req.transaction_id;
- gsm0480_send_ussd_reject(conn, msg, &ussd_req);
+ gsm0480_send_ussd_reject(conn, invoke_id, transaction_id);
release_conn:
msc_release_connection(conn);
return rc;
-
-#if 0
- ussdq = get_by_iid(conn, req.invoke_id);
-
- // TODO FIXME !!!! Replace by message_type
- switch (req.opcode) {
- case GSM0480_OP_CODE_PROCESS_USS_REQ:
- if (ussdq) {
- /* new session with the same id as an open session, destroy both */
- DEBUGP(DMM, "Duplicate session? invoke_id: %d\n", req.invoke_id);
- goto failed;
- }
-
- if (req.component_type != GSM0480_CTYPE_INVOKE) {
- DEBUGP(DMM, "processUSS with component_type 0x%02x\n", req.component_type);
- goto failed;
- }
-
- ussdq = ussd_session_alloc(conn);
- if (!ussdq) {
- DEBUGP(DMM, "Failed to create new session\n");
- goto failed;
- }
-
- ussdq->conn = conn;
- ussdq->invoke_id = req.invoke_id;
- ussdq->transaction_id = req.transaction_id;
- break;
-
- case GSM0480_OP_CODE_USS_REQUEST:
- if (!ussdq) {
- DEBUGP(DMM, "no session found for USS_REQUEST with invoke_id=%d\n", req.invoke_id);
- goto failed;
- }
- if (req.component_type != GSM0480_CTYPE_RETURN_RESULT) {
- DEBUGP(DMM, "USS with component_type 0x%02x\n", req.component_type);
- goto failed;
- }
-
- ussdq->current_transaction_id = req.transaction_id;
- break;
-
- default:
- DEBUGP(DMM, "Unhandled opcode: 0x%02x, component_type: 0x%02x, text: %s\n",
- req.opcode, req.component_type, req.ussd_text);
- goto failed;
- }
-
- // ACHTUNG! FIXME!! FIXME!! Introduce transaction ID instead
- // Override Invoke ID
- req.invoke_id = ussdq->uniq_id;
- rc = subscr_tx_uss_message(&req, conn->subscr);
- if (rc) {
- DEBUGP(DMM, "Unable tp send uss over sup reason: %d\n", rc);
- goto failed;
- }
-
- return 0;
-#endif
-#if 0
- 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 {
- rc = subscr_tx_uss_message(req, conn->subscr);
-
-
- //TODO:
- }
-#endif
-#if 0
-failed:
- // TODO handle error on SUP end
- if (ussdq) {
- ussd_session_free(ussdq);
- }
-
- ussd_req.invoke_id = req.invoke_id;
- ussd_req.transaction_id = req.transaction_id;
- gsm0480_send_ussd_reject(conn, msg, &ussd_req);
- /* check if we can release it */
- msc_release_connection(conn);
- return rc;
-#endif
}
-#if 0
-
-/* 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);
-
-
-/* A network-specific handler function */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ussd_request *req)
+void _ussd_trans_free(struct gsm_trans *trans)
{
- char *own_number = conn->subscr->extension;
- char response_string[GSM_EXTENSION_LENGTH + 20];
+ if (trans->ss.dirty) {
+ trans->ss.dirty = 0;
- /* 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);
+ //ussd_sup_send_reject(trans->net, trans->callref, trans->ss.invoke_id, 0);
+ ussd_sup_send_reject(trans->net, trans->callref);
+ }
}
-#endif
+
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 3b5778eac..9583a5b29 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -50,7 +50,8 @@
#include <openbsc/sms_queue.h>
#include <openbsc/mncc_int.h>
#include <openbsc/handover.h>
-#include <openbsc/gsm_sup.h>
+#include <openbsc/gprs_gsup_client.h>
+#include <openbsc/gsm_ussd_map.h>
#include <osmocom/vty/logging.h>
@@ -1035,19 +1036,20 @@ DEFUN(sup_ussd_destination, sup_ussd_destination_cmd,
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
if (gsmnet->ussd_sup_client) {
- LOGP(DSUP, LOGL_FATAL, "Can't create two USSD SUP clients\n");
+ LOGP(DSS, LOGL_FATAL, "Can't create two USSD SUP clients\n");
vty_out(vty, "%%USSD SUP client already configured%s", VTY_NEWLINE);
return CMD_WARNING;
}
gsmnet->ussd_sup_client = gprs_gsup_client_create(
- argv[0], atoi(argv[1]), &sup_read_cb);
+ argv[0], atoi(argv[1]), &ussd_map_read_cb);
if (!gsmnet->ussd_sup_client) {
- LOGP(DSUP, LOGL_FATAL, "Cannot set up USSD SUP socket\n");
+ LOGP(DSS, LOGL_FATAL, "Cannot set up USSD SUP socket\n");
vty_out(vty, "%%Cannot set up USSD SUP socket%s", VTY_NEWLINE);
return CMD_WARNING;
}
+ gsmnet->ussd_sup_client->data = gsmnet;
return CMD_SUCCESS;
}