aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Kostanbaev <sergey.kostanbaev@gmail.com>2015-10-28 13:31:16 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2017-02-07 18:59:54 +0300
commit2b5eb8ddb02bce309f70c24604001b97d642835e (patch)
tree45e511bfcf270e931867310b6685ec0c2dc4fba9
parentfd245fcfa8650976d8b1e7734ec9c0071375b365 (diff)
libmsc: use message type as an entry point and handle release complete message
-rw-r--r--openbsc/include/openbsc/ussd.h3
-rw-r--r--openbsc/src/libmsc/ussd.c171
2 files changed, 152 insertions, 22 deletions
diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h
index a84f51fbd..eee0b9a0c 100644
--- a/openbsc/include/openbsc/ussd.h
+++ b/openbsc/include/openbsc/ussd.h
@@ -5,6 +5,9 @@
#include <osmocom/core/msgb.h>
+#define USSD_MO 1
+#define USSD_MT 0
+
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
index c81f777c7..2bad560d5 100644
--- a/openbsc/src/libmsc/ussd.c
+++ b/openbsc/src/libmsc/ussd.c
@@ -45,11 +45,12 @@ struct gsm_ussd {
uint8_t invoke_id;
uint8_t transaction_id;
- uint8_t current_transaction_id;
+ uint8_t mobile_originated;
struct gsm_subscriber_connection *conn;
};
+static unsigned s_ussd_open_sessions = 0;
static uint64_t s_uniq_ussd_sessiod_id = 0;
static LLIST_HEAD(s_active_ussd_sessions);
@@ -59,7 +60,9 @@ static struct llist_head *get_active_ussd_sessions(void)
}
-static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* conn)
+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);
@@ -68,37 +71,41 @@ static struct gsm_ussd* ussd_session_alloc(struct gsm_subscriber_connection* con
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\n", m->uniq_id);
+ DEBUGP(DMM, "Alloc USSD session: %d (open: %d)\n", m->uniq_id, s_ussd_open_sessions);
return m;
}
static void ussd_session_free(struct gsm_ussd* s)
{
- DEBUGP(DMM, "Free USSD session: %d\n", s->uniq_id);
+ --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);
}
-static struct gsm_ussd* get_by_uniq_id(uint8_t invoke_id)
+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 == invoke_id) {
- DEBUGP(DMM, "uniq invoke_id %d has %s extention\n",
- invoke_id, c->conn->subscr->extension);
+ if (c->uniq_id == uniq_id) {
+ DEBUGP(DMM, "uniq_id %d has %s extention\n",
+ uniq_id, c->conn->subscr->extension);
return c;
}
}
- DEBUGP(DMM, "uniq invoke_id %d hasn't been found\n", invoke_id);
+ DEBUGP(DMM, "uniq_id %d hasn't been found\n", uniq_id);
return NULL;
}
-static struct gsm_ussd* get_by_id(struct gsm_subscriber_connection *conn, uint8_t invoke_id)
+static struct gsm_ussd* get_by_iid(struct gsm_subscriber_connection *conn, uint8_t invoke_id)
{
struct gsm_ussd* c;
llist_for_each_entry(c, get_active_ussd_sessions(), ussqueue) {
@@ -113,14 +120,74 @@ static struct gsm_ussd* get_by_id(struct gsm_subscriber_connection *conn, uint8_
return NULL;
}
+static struct gsm_ussd* get_by_tid(struct gsm_subscriber_connection *conn, uint8_t transaction_id)
+{
+ 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;
+ }
+ }
+
+ DEBUGP(DMM, "transaction_id %d hasn't been found\n", transaction_id);
+ return NULL;
+}
+
+// From SUP
int on_ussd_response(const struct ss_request *req, const char *extention)
{
struct ussd_request ussd_req;
- struct gsm_ussd* ussdq = get_by_uniq_id(req->invoke_id);
+ struct gsm_ussd* ussdq;
memset(&ussd_req, 0, sizeof(ussd_req));
int rc;
- uint8_t mtype;
+ switch (req->message_type) {
+ case GSM0480_MTYPE_REGISTER:
+ DEBUGP(DMM, "Network originated USSD messages isn't supported yet!\n");
+
+ //TODO Send to sup rejection
+ 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
+ return 0;
+ }
+ break;
+ default:
+ DEBUGP(DMM, "Unknown message type 0x%02x\n", req->message_type);
+ // TODO SUP Reject
+ return 0;
+ }
+
+ ussd_req.transaction_id = ussdq->transaction_id;
+ ussd_req.invoke_id = ussdq->invoke_id;
+
+ if (req->component_type != GSM0480_CTYPE_REJECT) {
+ rc = gsm0480_send_ussd_response(ussdq->conn,
+ NULL,
+ (const char *)req->ussd_text,
+ &ussd_req,
+ req->opcode,
+ req->component_type,
+ req->message_type);
+ } else {
+ rc = gsm0480_send_ussd_reject(ussdq->conn, NULL, &ussd_req);
+ }
+
+ if (req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
+ ussd_session_free(ussdq);
+ msc_release_connection(ussdq->conn);
+ }
+
+#if 0
switch (req->opcode) {
case GSM0480_OP_CODE_USS_NOTIFY:
DEBUGP(DMM, "Network originated USSD Notify is not supported yet!\n");
@@ -149,7 +216,7 @@ int on_ussd_response(const struct ss_request *req, const char *extention)
}
mtype = GSM0480_MTYPE_FACILITY;
- ussd_req.transaction_id = ussdq->current_transaction_id;
+ ussd_req.transaction_id = ussdq->transaction_id;
break;
default:
// TODO SUP Reject
@@ -175,12 +242,14 @@ int on_ussd_response(const struct ss_request *req, const char *extention)
}
return rc;
+
+#endif
}
/* Entrypoint - handler function common to all mobile-originated USSDs */
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
- int rc;
+ int rc = 0;
struct gsm48_hdr *gh;
struct ss_request req;
struct gsm_ussd* ussdq = NULL;
@@ -193,16 +262,73 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
gh = msgb_l3(msg);
rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
-
- //if (req.ussd_text[0] == 0xFF)
- // req.ussd_text[0] = '\0';
-
if (!rc) {
DEBUGP(DMM, "Unhandled SS\n");
- goto failed;
+ ussdq = get_by_tid(conn, req.transaction_id);
+ if (ussdq) {
+ // TODO send notification to SUP
+ goto failed_transaction;
+ }
+
+ goto transaction_not_found;
}
- ussdq = get_by_id(conn, req.invoke_id);
+ switch (req.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");
+ goto transaction_not_found;
+ }
+ ussdq->invoke_id = req.invoke_id;
+ 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;
+ }
+ }
+ 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");
+ goto release_conn;
+ }
+
+ ussd_session_free(ussdq);
+ // TODO send notification to SUP
+ goto release_conn;
+ }
+
+ 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_transaction;
+ }
+ return 0;
+
+failed_transaction:
+ ussd_session_free(ussdq);
+
+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);
+
+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) {
@@ -258,7 +384,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
}
return 0;
-
+#endif
#if 0
struct ussd_request req;
struct gsm48_hdr *gh;
@@ -287,7 +413,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
//TODO:
}
#endif
-
+#if 0
failed:
// TODO handle error on SUP end
if (ussdq) {
@@ -300,6 +426,7 @@ failed:
/* check if we can release it */
msc_release_connection(conn);
return rc;
+#endif
}
#if 0